zoukankan      html  css  js  c++  java
  • Codeforces Round #612 (Div. 2)

    A. Angry Students (CF 1287 A)

    题目大意

    给定一个包含(A)(P)字符串,对于每一个(A)的位置,如果它右边字母是(P),那么下一秒它会变成(A),最后一个字母如果是(A),则没什么事发生。问最后一次产生字母变化的时间是何时。

    解题思路

    找到最大的两个(A)的间隔即是答案。
    (一开始考虑最后一个A距离右端点的距离然后WA心态全崩)

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    int main(void) {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        int kase; cin>>kase;
        for (int i = 1; i <= kase; i++) {
            int n;
            cin>>n;
            string s;
            cin>>s;
            int ans=0;
            int cnt=0;
            bool qwq=true;
            for(int i=0;i<n;++i){
                if (s[i]=='P') ++cnt;
                else {
                    if (qwq) {qwq=false;cnt=0;}
                    else{
                        ans=MAX(ans,cnt);
                        cnt=0;
                    }
                }
            }
            ans=MAX(ans,cnt);
            if (qwq) ans=0;
            cout<<ans<<endl;
        }
        return 0;
    }
    


    B. Hyperset (CF 1287 B)

    题目大意

    (n)张卡片,有(k)个属性,每个属性的取值为(S)(E)(T)中的一种。现在要选取三张卡片,对于卡片的所有的每个属性,如果三张卡片是全部相同或者全部不同,这三张卡片就可以形成一个集合。问这些卡片能形成多少个集合。

    解题思路

    注意到,如果我们枚举了两张卡片,那么第三张卡片其实是已经确定的,我们只要判断这张卡片是否存在即可,丢到(unordered\_map)里即可。注意不要重复,我们假设三张卡片的顺序(i<j<k)即可。

    但是关于(string)的赋值,一开始写(ss=ss+'T')结果(T)了,改成(ss.push\_back('T'))(ss+='T')(A)了。看来要少用(ss=ss+'T')这种形式。

    改成(map)恰好(2931ms)过了,而(unordered\_map)(1512ms)过了。所以无关顺序的话我们还是尽量用(O(1))(unordered\_map)
    其实也可以建一棵(trie)树去判断是否存在。

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    int main(void) {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        int n,m;
        cin>>n>>m;
        unordered_map<string,int> qwq;
        qwq.clear();
        string s[n+1];
        for(int i=0;i<n;++i){
            cin>>s[i];
            qwq[s[i]]=i+1;
        }
        int ans=0;
        for(int i=0;i<n-2;++i)
            for(int j=i+1;j<n-1;++j){
                string ss;
                for(int k=0;k<m;++k){
                    if (s[i][k]==s[j][k]) ss+=s[i][k];
                    else if (s[i][k]!='S'&&s[j][k]!='S') ss+='S';
                    else if (s[i][k]!='T'&&s[j][k]!='T') ss+='T';
                    else if (s[i][k]!='E'&&s[j][k]!='E') ss+='E';
                }
                if (qwq[ss]>j) ++ans;
            }
        cout<<ans<<endl;
        return 0;
    }
    


    C. Garland (CF 1287 C)

    题目大意

    给定一个排列,有几个位置是(0),要求填入缺的数,使得排列里,俩俩相邻的奇偶性不同的对数最小,输出该最小值。

    解题思路

    我们考虑对于每一个(0)区间填入的数对答案的贡献。

    我们发现仅有四种情况(奇,奇)(奇,偶)(偶,奇)(偶,偶)。由于奇偶具有对称性,我们只用考虑前两种情况,后两种情况类似。

    对于第一种情况,如果我们全部填奇数,那么它对答案的贡献为(0),否则最小就会贡献(2)。那么我们就最好尽可能的满足全部填奇数的要求。

    对于第二种情况,我们发现无论我们怎么填,它对答案的贡献的最小值始终为(1),于是对于这种情况我们就对答案加(1)即可。

    但这里还有种特殊情况就是在边缘的,即(空,奇)(空,偶)(奇,空)(偶,空)。由于这四种情况讨论是类似的,我们仅考虑其中一种即可。

    对于(空,奇)的情况,如果我们全部填奇数,那么它对答案的贡献为(0),否则就会最小贡献(1)。自然我们也是最好尽可能的满足全部填奇数的要求。

    以奇数为例,现在问题就转化成了,我有(cnt1)个奇数可以去填,现在有若干个长度((0)的个数)为(l_i)的(奇,奇)或(空,奇)或(奇,空)的区间,如果我拿(l_i)个奇数去填该区间,那么我可以消除对答案的(1)(2)的贡献,现在要求消除的贡献最大。

    我们再转换一下,即是有一个大小为(cnt1)的背包以及若干个重量为(l_i)的物品,它的价值为(1)(2),现在要求把这些物品放到背包里,使得价值最大。

    这就是(01)背包问题呀!我们只用把所有(奇,奇)或(空,奇)或(奇,空)区间找出来,跑一遍(01)背包即可,然后对于偶数的情况类似。

    对应为代码的注释部分。

    这题还可以直接动规去做。我们设(dp[pos][zero][one][parity])表示当前要填的位置为(pos),还剩(zero)个偶数可以填,(one)个奇数可以填,(pos-1)的位置的奇偶性为(parity)(0)(1)
    状态转移方程就考虑该位如果不是(0),那就直接传到下一个位置,否则就尝试填(0)(1)即可。详见代码。

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    const int N=105;
    
    int n,dp[N][N][N][2],a[N];
    
    int work(int pos,int zero,int one,int parity){
        if (zero<0||one<0) return 1e9+7;
        if (pos==n) return 0;
        if (dp[pos][zero][one][parity]!=-1) return dp[pos][zero][one][parity];
        if (a[pos]!=0) return dp[pos][zero][one][parity]=work(pos+1,zero,one,a[pos]&1)+((a[pos]&1)^parity);
        return dp[pos][zero][one][parity]=min(work(pos+1,zero-1,one,0)+(parity==1),work(pos+1,zero,one-1,1)+(parity==0));
    }
    
    int main(){
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        read(n);
        int cnt[2];
        cnt[0]=n/2;
        cnt[1]=n-cnt[0];
        for(int i=0;i<n;++i){
            read(a[i]);
            if (a[i]!=0) --cnt[a[i]&1]; 
        }
        memset(dp,-1,sizeof(dp));
        printf("%d
    ",min(work(0,cnt[0],cnt[1],0),work(0,cnt[0],cnt[1],1)));
        return 0;
    }
    
    
    
    /* int main(void) {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        int n;
        cin>>n;
        vector<int> qwq(n);
        for(int i=0;i<n;++i) cin>>qwq[i];
        int cnt0=n/2,cnt1=n-cnt0;
        for(int i:qwq){
            if (i==0) continue;
            else if (i&1) --cnt1;
            else --cnt0;
        }
        vector<pair<int,int>> qaq[2];
        int l=-1,r=0,ans=0;
        while(r<n){
            while(l<n&&qwq[l+1]!=0) ++l;
            if (l>=n) break;
            r=l+1;
            while(r<n&&qwq[r]==0) ++r;
            if (r==n) if (l==-1) {ans=-1; break;}
            else qaq[qwq[l]&1].push_back(make_pair(r-l-1,1));
            else {
                if (l==-1) qaq[qwq[r]&1].push_back(make_pair(r-l-1,1));
                else if ((qwq[l]&1)^(qwq[r]&1)) ++ans;
                else qaq[qwq[l]&1].push_back(make_pair(r-l-1,2));
            }
            l=r;
        }
        if (ans==-1) if (n==1) cout<<"0"<<endl; else cout<<"1"<<endl;
        else{
            vector<int> dp0(cnt0+2),dp1(cnt1+2);
            for(auto i:qaq[0])
                for(int j=cnt0;j>=i.first;--j)
                    dp0[j]=MAX(dp0[j],dp0[j-i.first]+i.second); 
            for(auto i:qaq[1])
                for(int j=cnt1;j>=i.first;--j)
                    dp1[j]=MAX(dp1[j],dp1[j-i.first]+i.second);         
            int su0=0,su1=0;
            for(auto i:qaq[0]) su0+=i.second;
            for(auto i:qaq[1]) su1+=i.second;
            int ma0=0,ma1=0;
            for(auto i:dp0) ma0=MAX(ma0,i);
            for(auto i:dp1) ma1=MAX(ma1,i);
            ans+=su0-ma0+su1-ma1;
            for(int i=1;i<n;++i){
                if (qwq[i]!=0&&qwq[i-1]!=0)
                    if ((qwq[i]&1)^(qwq[i-1]&1)) ++ans;
            }
            cout<<ans<<endl;
        }
        return 0;
    } */
    


    D. Numbers on Tree (CF 1287 D)

    题目大意

    给定一棵树,每个节点都有一个值(a_i),同时也有一个值(c_i),它是以这个节点为根的子树的节点值(a_j<a_i)的个数,给出每个点的(c_i)以及树,求每个节点的(a_i),如有多种情况输出任意一种即可。没有情况则输出(NO)

    解题思路

    构造题,某个节点的(a_i)值仅与它的子树以及(c_i)值有关,我们不妨设每个节点的值都不一样,这样对于一棵子树来说,我们把它的子树的值排个序,第(c_i+1)个数就是它的值,然后大于等于(c_i+1)的值都加(1),以保证每个节点的值仍不一样。如此我们就可以构造一组(a_i)值满足题目要求了。
    构造题尽量想方便我们得知状态以及决策的方法。

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    const int N=2003;
    
    int n,root;
    
    vector<int> son[N],ji;
    
    int q[N],ans[N];
    
    int DFS(int u){
        int cnt=0;
        for(int i:son[u]) cnt+=DFS(i);
        if (u==0) return 0;
        if (q[u]>cnt) {puts("NO"); exit(0);}
        ji.insert(ji.begin()+q[u],u);
        return cnt+1;
    }
    
    int main(void) {
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        read(n);
        for(int f,i=1;i<=n;++i){
            read(f);
            read(q[i]);
            son[f].push_back(i);
        }
        DFS(0);
        int qwq=0;
        for(int i:ji) ans[i]=++qwq;
        puts("YES");
        for(int i=1;i<=n;++i) printf("%d%c",ans[i],i==n?'
    ':' ');
        return 0;
    }
    


    考试周打CF无所畏惧

  • 相关阅读:
    【bzoj1036】【ZJOI2008】树的统计
    AE基础(8)PageLayout属性设置和添加元素
    AE基础(7)布局控件与地图控件关联
    UtilityAction扩展
    UtilityAction
    AE基础(6)数据查询与选择
    NavigationAction
    LayerAction
    AE基础(5)鹰眼功能
    AE基础(4)画几何图形
  • 原文地址:https://www.cnblogs.com/Lanly/p/12158322.html
Copyright © 2011-2022 走看看