• Codeforces Round #764 (Div. 3)(CF1624)题解


    CF1624D. Palindromes Coloring

    题意:
    给定一个字符串,长度为n,顺序任意调换。取k个字串,要求为回文,求回文子串字串最短长度。

    解法:
    考虑每个字母的贡献,如果有成对的字母,则可以放在首尾,而单个只能放在中间。如果无法均匀分配,则剩下的配对字母应当拆分成单个以最大化答案。

    #include <bits/stdc++.h>
    #define For(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int N=200005;
    int t,n,k,sum[30];
    char ch[N];
    signed main() {
        cin>>t;
        while(t--) {
            cin>>n>>k;
            scanf("%s",ch+1);
            memset(sum,0,sizeof sum);
            For(i,1,n) sum[ch[i]-'a'+1]++;
            int pr=0,sg=0;
            For(i,1,26) pr+=sum[i]/2,sg+=sum[i]%2;
            if(pr%k==0) cout<<(pr/k)*2+(sg>=k?1:0)<<'\n';
            else cout<<(pr/k)*2+(sg+(pr%k)*2>=k?1:0)<<'\n';
        }
        return 0;
    }
    

    CF1624E - Masha-forgetful
    题意:
    给定一些字符串,问能否用这些字符串中的一些长度大于2的字串拼成另一个给定的字符串.

    解法:
    因为无论取字串的长度多少,都能够用长度为2或3的小字串拼接而成.所以把字串长度限制为2和3,然后向前dp,回溯输出结果.

    //考虑奇数和偶数都可以通过长度2或长度3拼出来,然后DP
    #include <bits/stdc++.h>
    #define For(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int N=1005;
    int t,n,m;
    bool f[N];
    char ch[N][N],now[N];
    struct bk {
        int l,r,id;
    } two[10][10],three[10][10][10]; //存储这2/3位的对应字串
    vector <bk> ans;
    signed main() {
        cin>>t;
        while(t--) {
            cin>>n>>m;
            For(i,1,n) scanf("%s",ch[i]+1);
            memset(two,0,sizeof two);
            memset(three,0,sizeof three);
            memset(f,0,sizeof f);
            For(i,1,n) For(j,1,m) {
                if(j+1<=m) two[ch[i][j]-'0'][ch[i][j+1]-'0']=(bk) {j,j+1,i};
                if(j+2<=m) three[ch[i][j]-'0'][ch[i][j+1]-'0'][ch[i][j+2]-'0']=(bk) {j,j+2,i};
            } //初始化
            f[0]=1;
            scanf("%s",now+1);
            For(i,1,m) {
                if(f[i-2]==1 && two[now[i-1]-'0'][now[i]-'0'].l) f[i]=1;
                if(f[i-3]==1 && three[now[i-2]-'0'][now[i-1]-'0'][now[i]-'0'].l) f[i]=1;
            }
            if(f[m]!=1) puts("-1");
            else {
                ans.clear();
                int at=m;
                while(at) {
                    if(f[at-2]==1 && two[now[at-1]-'0'][now[at]-'0'].l) {
                        ans.push_back(two[now[at-1]-'0'][now[at]-'0']); at-=2;
                    }
                    if(f[at-3]==1 && three[now[at-2]-'0'][now[at-1]-'0'][now[at]-'0'].l) {
                        ans.push_back(three[now[at-2]-'0'][now[at-1]-'0'][now[at]-'0']); at-=3;
                    }
                }
                cout<<ans.size()<<'\n';
                for(int i=ans.size()-1;i>=0;i--) cout<<ans[i].l<<" "<<ans[i].r<<" "<<ans[i].id<<'\n';
            }
        }
        return 0;
    }
    

    CF1624F. Interacdive Problem
    题意:
    有一个1~n-1的数,你可以做操作,使x=x+(你给定的数),并给出floor(x/n),求最后的x为多少

    解法:
    通过二分逐步缩小范围,记得存储累加的数,这样可以保证再1~n-1之间二分,然后将得到的floor值与mid应当具有的floor值相比较即可.

    #include <bits/stdc++.h>
    using namespace std;
    const int N=100;
    int n,tot;
    signed main() {
        cin>>n;
        int l=1,r=n-1,res=0,ans=0;
        while(l<=r) {
            int mid=(l+r)>>1;
            int should=mid+tot;
            int need=n-should%n;
            cout<<"+ "<<need<<'\n';
            tot+=need;
            cin>>res;
            if(res==(should+need)/n) ans=mid,l=mid+1;
            else r=mid-1;
        }
        cout<<"! "<<ans+tot<<'\n';
        return 0;
    }
    

    CF1624G. MinOr Tree
    题意:
    给一张图,求在能够组成一棵树的情况下,树的边的或和最小。

    解法:
    考虑每一位的贡献,从高到低用并查集判断在某一位全部为0时是否能够组成一棵树。如果可以,则禁用此位为1的所有边,继续向下查找。

    #include <bits/stdc++.h>
    #define For(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int N=200005;
    int t,n,m,need[N];
    struct node {
        bool ok;
        int u,v,w,bi[31];
    } a[N];
    int fa[N],rk[N];
    int find(int x) {
        if(fa[x]==x) return x;
        else return fa[x]=find(fa[x]);
    }
    void merge(int x,int y) {
        int xx=find(x),yy=find(y);
        if(rk[xx]<rk[yy]) fa[xx]=yy,rk[yy]=max(rk[yy],rk[xx]+1);
        else fa[yy]=xx,rk[xx]=max(rk[xx],rk[yy]+1);
    }
    signed main() {
        cin>>t;
        while(t--) {
            cin>>n>>m;
            For(i,1,m) {a[i].ok=1; memset(a[i].bi,0,sizeof a[i].bi);}
            For(i,1,m) {
                cin>>a[i].u>>a[i].v>>a[i].w;
                int temp=-1;
                while(a[i].w) {
                    a[i].bi[++temp]=a[i].w%2;
                    a[i].w/=2;
                }
            }
            memset(need,0,sizeof need);
            for(int i=30;i>=0;i--) {
                int sum=0; //合并的总次数
                For(j,1,n) fa[j]=j,rk[j]=1;
                For(j,1,m) if(a[j].ok==1 && a[j].bi[i]==0) {
                    if(find(a[j].u)!=find(a[j].v)) {
                        merge(a[j].u,a[j].v); sum++;
                    }
                }
                if(sum>=n-1) { //全部用0也可以做到,那为1的就不能再用了
                    For(j,1,m) if(a[j].ok==1 && a[j].bi[i]==1)
                        a[j].ok=0;
                } else { //不行 只能开1
                    need[i]=1;
                }
            }
            int ans=0;
            For(i,0,30) ans+=need[i]*pow(2,i);
            cout<<ans<<'\n';
        }
        return 0;
    }
    
  • 相关阅读:
    最大子数组的求解(包括首尾相接成环)
    学习进度条第五周
    学习进度条第四周
    学习进度条第三周
    软件工程概论作业二
    软件工程个人作业01
    软件工程概论总结
    梦断代码阅读笔记01
    构建之法阅读笔记04
    构建之法阅读笔记03
  • 原文地址:https://www.cnblogs.com/wky32768/p/15838953.html
Copyright © 2020-2023  润新知