第一周总结

    • 内容概括
      • 涉及算法
      • 题数
    • 相关算法
      • 贪心,模拟,(优先队列,set)
        • HDU6299 Balanced Sequence
        • HDU6301 Distinct Values
        • HDU6308 Time Zone

内容概括

涉及算法

贪心,模拟

题数

1

相关算法

贪心,模拟,(优先队列,set)

HDU6299 Balanced Sequence

原题链接

题意: 给n个只包含’(‘,’)’的字符串 问怎样组合这些字符串可以获得最长平衡子序列(不必连续)的长度

思考过程及相关解法:可以先把每个串合法括号匹配数统计一下,再记录其不合法个数,此时的序列形式为”…)))((((…” 格式,可以对每个序列处理出一个有序对(a,b),a代表该序列左端右括号,b代表该序列右端左括号。然后对所有序列排序,之后模拟计算结果

排序的贪心思想并不会证明 见参考代码

参考代码:

#include 
#include  
#include 
using namespace std;
const int MAXS =  100005;
struct node{
    int l,r,cnt;
    bool operator < (node const& b) const{
        if (l < r && b.l >= b.r ) return true; //a的左端比右端短 b的左端比右端长 则a一定排前面 
        if (l >= r && b.l < b.r) return false;
        //接下来考虑负贡献 a,b都是右端长 此时要看谁左端提供负贡献最小 然后把它放在前面 都是左端长同理 
        if (l < r && b.l < b.r) return l < b.l;    
        if (l >= r && b.l >= b.r) return r > b.r;  
    }
}a[MAXS];
char s[MAXS];
int main(){
    int t;
    scanf("%d",&t);
    while (t--){
        int n;
        scanf("%d",&n);
        for (int i = 1; i <= n; ++i){
            scanf("%s",s);
            int len = strlen(s);
            a[i].l = a[i].r = a[i].cnt = 0;
            //处理每个串中的合法匹配 得到每个串的不合法括号序列 一定是左边是右括号右边是左括号形式 
            for (int j = 0;j < len; ++j){
                if (s[j] == '(') a[i].r++;  //左边的是右括号 左括号在右边 
                else{
                    if (a[i].r > 0) {
                        a[i].r--; a[i].cnt++;
                    }else a[i].l++;
                }
            }

        }
        sort(a+1,a+n+1);
        int ans = 0;
        int lcnt = 0;
        //模拟维护左括号数即可 
        for (int i = 1; i <= n; ++i){
            if (a[i].l > lcnt) a[i].l = lcnt;
            ans += a[i].l + a[i].cnt;
            lcnt -= a[i].l;
            lcnt += a[i].r;
        }
        printf("%d\n",ans * 2);
    }
    return 0;
}

HDU6301 Distinct Values

原题链接

题意:对一个序列,有m行区间表示该区间内的所有数字都不同,问能得到的从1到n字典序最小的序列 输出这个序列

思考过程及相关解法:问题在于处理重叠区间的数值填数 因为必须要维护可使用的值的序列,且要维护这个序列每次都取最小值,可以考虑使用优先队列或者set 维护这个序列 处理区间时注意相同的区间端点,要保证处理到最长的另一端

参考代码:

#include 
#include 
#include 
#include  
#include 
using namespace std; 
const int MAXN = 1000005;
struct node{
    int l,r;
}a[MAXN];
int ans[MAXN];
bool cmp(node a,node b){
    if (a.l == b.l) return a.r < b.r;
    return a.l < b.l;
}
int flag[MAXN];
priority_queue<int,vector<int>,greater<int> > que;
int main(){
    int t;
    while (scanf("%d",&t)!=EOF){
            while (t--){
                int n,m;
                scanf("%d%d",&n,&m);
                for (int i = 0;i < m; ++i){
                    scanf("%d%d",&a[i].l,&a[i].r);
                }
                sort(a,a+m,cmp);
                for (int i = 1;i <= n; ++i){
                    que.push(i);
                    ans[i] = 0;
                    flag[i] = 0;
                }
                int pos = 1,k = 0;
                for (int i = 1;i <= n; ++i){
                    //处理一个区间 
                    while (k < m && a[k].l == i){
                        pos = max(i,pos);
                        while (pos <= a[k].r){
                            ans[pos] = que.top();
                            flag[ans[pos]] = 1;
                            que.pop();
                            pos++;
                        }
                        k++;
                    }//保证区间内的数不同 ans数组再往前走 用过的位置的数已经可以使用 
                     //printf("*%d %d*\n",i,ans[i]);
                    if (ans[i] == 0) ans[i] = 1;
                    else if (flag[ans[i]] == 1){
                        que.push(ans[i]);
                        flag[ans[i]] = 0;
                    }
                }
                for (int i = 1;i <= n; ++i){
                    printf("%d%c",ans[i],i == n ? '\n' : ' ');
                } 
                while (!que.empty()) que.pop();

        }
    }

    return 0;
} 

/*set维护 参考杜教代码
set<int> s;
for (int i = 1;i <= n; ++i) pre[i] = i,s.insert(i);
for (int i = 1;i <= m; ++i){scanf("%d%d",&l,&r); pre[r] = min(pre[r],l);} 
//将区间由右至左的pre[i]更新为区间左端点
for (int i = n-1; i >= 1; ++i) pre[i] = min(pre[i],pre[i+1]);
int cnt = 1;
for (int i = 1;i <= n; ++i){
    while (cnt < pre[i]){
    //将前一段区间用过的加入set 维护最小值 (从cnt到该区间左端的值可以使用了 加入进去)
        s.insert(ans[cnt]);
        cnt++;
    }
    ans[i] = *s.begin();
    s.erase(ans[i]);
}
*/

HDU6308 Time Zone

原题链接

题意:时区转换 将北京地区的时区时间转换为对应的时区的时间

思考过程及相关解法:直接模拟即可,将时间统一转化为最小精度(分钟)计算,注意对一天24*60min取模。时区可以是小数,所以处理起来可能不方便 这里看了杜教的代码,学习了一下sscanf的用法 大致就是将字符串从某位开始以需要的数据类型读取出来。 (在数据类型处可声明读取长度)

参考代码:

#include 
#include 
#include 
#include  
#include 
using namespace std; 
const int MAXN = 1000005;
int _;
int sgn,a,b,ans;
double d;
char s[30]; 
int main(){
    for (scanf("%d",&_);_;_--){
        scanf("%d%d%s",&a,&b,s);
        ans = a*60+b;
        sgn = s[3] == '+' ? 1 : -1;
        sscanf(s+4,"%lf",&d);
        int c = (int)(d * 10 + 0.1);
        c = sgn * c * 6 - 8 * 60;
        ans += c;
        ans %= (24 * 60);
        if (ans < 0) ans += (24 * 60);
        printf("%02d:%02d\n",ans/60,ans%60);
    }
    return 0;
} 

你可能感兴趣的:(每周(→∞)记录?)