• CodeForces Round #705 总结&题解


    突然发现博客咕了好久了,今天更新一下~~

    A. Anti-knapsack

    原题链接

    给定整数 (n,k),从({1,2,3,cdots,n}) 中选出最大的子集 (S),使得 ( exists Asubseteq S,sumlimits_{x in A}x=k)

    显然,(gt k) 的随便选,(lt k) 的选 (lceilfrac{k}{2} ceil,lceilfrac{k}{2} ceil+1,cdots,k-1) 即可。可以从可行性及最优性两方面证明。

    Code:(考场写的,比较潦草)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    template<typename T>
    inline T read(){
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
     
    #define rdi read<int>
    #define rdl read<ll>
     
    int n,k,T;
    int main(){
        T=rdi();
        while(T--){
            n=rdi(),k=rdi();
            int cnt=0,a[1010]={0};
            for(int i=k+1;i<=n;i++) a[++cnt]=i;
            for(int i=(k+1)/2;i<k;i++) a[++cnt]=i;
            printf("%d
    ",cnt);
            for(int i=1;i<=cnt;i++) printf("%d ",a[i]);
            puts("");
        }
        return 0;
    }
    
    

    B. Planet Lapituletti

    原题链接

    假设一天有 (h) 小时,每小时 (m) 分钟。给定一个起始时间 (HH:MM形式),求从起始时间起第一个合法的镜像时间。

    合法时间:该时间以数位管形式显示时,(0 le 分钟数 lt m)(0 le 时钟数 lt m)

    合法镜像时间:该时间是合法时间,且该时间在镜子中投影(即左右翻转)后仍可以作为一个合法时间。

    打表出 (0sim 9) 对应镜像数字的表(不合法为 (-1)),然后枚举时间即可。

    一个坑:(00:01) 可以到 (00:00)(相当于到了第二天)。

    Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    template<typename T>
    inline T read(){
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
               if(ch=='-') f=-1;
               ch=getchar();
            }
        while(ch>='0'&&ch<='9'){
               x=(x<<1)+(x<<3)+(ch^48);
               ch=getchar();
            }
        return x*f;
    }
     
    #define rdi read<int>
    #define rdl read<ll>
     
    int T,n,m,x,y;
    const int fx[]={0,1,5,-1,-1,2,-1,-1,8,-1};
    pii rev(int x,int y){
        int a=x/10,b=x%10,c=y/10,d=y%10;
        if(fx[a]==-1||fx[b]==-1||fx[c]==-1||fx[d]==-1) return make_pair(-1,-1);
        return make_pair(fx[d]*10+fx[c],fx[a]+fx[b]*10);
    }
     
    int main(){
        T=rdi();
        while(T--){
            n=rdi(),m=rdi();
            scanf("%d:%d",&x,&y);
            for(;;y++,(x+=y/m)%=n,y%=m){
                if(rev(x,y).first==-1) continue;
                if(rev(x,y).first<n&&rev(x,y).second<m){
                    printf("%02d:%02d
    ",x,y);
                    break;
                }
            }
        }
        return 0;
    }
    
    

    C. K-beautiful Strings

    原题链接

    给定一个长度为 (n) 的字符串 (s) 及一个常数 (k),求字典序大于等于 (s) 、长度为 (n) 的字典序最小的好的字符串。

    好的字符串:由小写字母构成,且每种字符都出现了 (k) 的倍数次。

    既然要求字典序大于等于 (s) 且字典序最小,那么可以从后往前枚举前缀。

    假设当前枚举到了 (i),先从 (s_i) 开始枚举当前这一位取什么字符,然后统计 (s_{1dots i}) 中每种字符的出现次数,设为 (cnt),那么显然,后面 (s_{i+1dots n}) 要补充 (sum=sumlimits_{i='a'}^{'z'} ((k-cnt_imod k)mod k)) 个字符,此时存在合法字符串,当且仅当 (sum le n-i) 且 $ sum equiv n-i pmod k$。如果满足,我们就先填充 (sum-(n-i)) 个字符 ‘a’ ,然后从 ‘a’ 到 ‘z’ 依次处理当前字符需填充数量并填充即可。

    Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    template<typename T>
    inline T read(){
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
               if(ch=='-') f=-1;
               ch=getchar();
            }
        while(ch>='0'&&ch<='9'){
               x=(x<<1)+(x<<3)+(ch^48);
               ch=getchar();
            }
        return x*f;
    }
     
    #define rdi read<int>
    #define rdl read<ll>
     
    const int N=100010;
    int T,n,k;
    char s[N];
    int main(){
        T=rdi();
        while(T--){
            n=rdi(),k=rdi(),scanf("%s",s+1);
            if(n%k){
                puts("-1");
                continue;
            }
            int cnt[30]={0};
            for(int i=1;i<=n;i++) cnt[s[i]-'a']++;
            bool flg=1;
            for(int j=0;j<26;j++) flg&=((cnt[j]%k)==0);
            if(flg){
                printf("%s
    ",s+1);
                continue;
            }
            for(int i=n;i>=1;i--){
                int cur=s[i]-'a',success=0;
                for(int j=cur+1;j<=26;j++){
                    cnt[cur]--;cnt[j]++;s[i]=j+'a';
                    int kkk=0;
                    for(int j=0;j<26;j++){
                        if(cnt[j]%k) kkk+=(k-cnt[j]%k)%k;
                    }
                    if(kkk<=n-i&&(n-i-kkk)%k==0){
                        int pos=i;
                        for(int o=1;o<=(n-i-kkk)-(n-i-kkk)%k;o++) s[++pos]='a';
                        for(int o=0;o<26;o++){
                            if(cnt[o]%k){
                                for(int p=1;p<=(k-cnt[o]%k);p++) s[++pos]=o+'a';
                            }
                        }
                        success=1;
                        goto ed;
                    }
                    cnt[cur]++,cnt[j]--;s[i]=cur+'a';
                }
                cnt[s[i]-'a']--;
            }
    //        char cur=s[0]+1;
      //      for(int i=1;i<=k;i++) s[i]=
    ed:
            printf("%s
    ",s+1);
        }
        return 0;
    }
     
    

    D. CF1493D GCD of an Array

    原题链接

    给定一个序列 (a),要求支持每次将某个位置 (i) 乘上一个数并询问当前整个序列的 (gcd)

    先筛一下质数,开一些 (multiset) ,第 (i) 个维护 (a) 中每个数分解质因数后 (1sim 2 imes10^5) 中第 (i) 大的质数的指数。

    修改将要乘的数分解质因数后直接加上即可。但查询若把 (1sim 2 imes10^5) 每个质数都查询一次最小值肯定会TLE,所以要维护答案的变化量,只查询被修改过的对应的质数。

    Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    template<typename T>
    inline T read(){
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
     
    #define rdi read<int>
    #define rdl read<ll>
     
    const int N=200010,MOD=1e9+7,INF=0x3f3f3f3f,P=18010;
    int n,q,a[N];
     
    int p[N],cp,vis[N];
    void pr(int lim){
        vis[0]=vis[1]=1;
        for(int i=2;i<=lim;i++){
            if(!vis[i]){
                p[++cp]=i;
                for(int j=i;j<=lim/i;j++) vis[i*j]=1;
            }
        }
    }
     
    ll qpow(ll x,ll y){
        ll res=1;
        while(y){
            if(y&1) (res*=x)%=MOD;
            (x*=x)%=MOD;y>>=1;
        }
        return res;
    }
     
    multiset<int> s[P];
    map<int,int> fac[N],tmp;
    ll ans=1;
    ll gcd(ll x,ll y){return !x?y:gcd(y%x,x);}
    int main(){
        n=rdi(),q=rdi();
        for(int i=1;i<=n;i++){
            a[i]=rdi();
            if(i==1) ans=a[i];
            else ans=gcd(ans,a[i]);
        }
        pr(N-10);
        for(int i=1;i<=n;i++){
            int lim=sqrt(a[i]),x=a[i];
            for(int j=1;p[j]<=lim&&j<=cp;j++){
                if(x%p[j]==0){
                    int cnt=0;
                    while(x%p[j]==0) x/=p[j],cnt++;
                    fac[i][j]=cnt;
                }
                lim=sqrt(x);
            }
            if(x>1){
                int tmp=lower_bound(p+1,p+cp+1,x)-p;
                fac[i][tmp]++;
            }
            for(auto x:fac[i]) s[x.first].insert(x.second);
        }
        while(q--){
            int id=rdi(),val=rdi();
            int lim=sqrt(val),x=val;tmp.clear();
            for(int j=1;p[j]<=lim&&j<=cp;j++){
                if(x%p[j]==0){
                    int cnt=0;
                    while(x%p[j]==0) x/=p[j],cnt++;
                    tmp[j]=cnt;
                }
                lim=sqrt(x);
            }
            if(x>1){
                int posss=lower_bound(p+1,p+cp+1,x)-p;
                tmp[posss]++;
            }
            for(auto x:tmp){
                int x1=x.first,x2=x.second;
                int pre=fac[id][x1],post=pre+x2;
                fac[id][x1]+=x2;
                int minx1=s[x1].size()<n?0:(*s[x1].begin());
                if(pre) s[x1].erase(s[x1].find(pre));
                s[x1].insert(post);
                int minx2=s[x1].size()<n?0:(*s[x1].begin());
                ans=ans*qpow(p[x1],minx2-minx1)%MOD;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    

    完结撒花~~

  • 相关阅读:
    单播、广播和多播IP地址
    nagios安装部署及详细配置说明(转)
    centos6.5下cacti部署说明
    HAproxy配置详解
    mysql全量和增量备份详解(带脚本)
    lvs原理及安装部署详解(参考)
    curl命令的用法
    mysql日志解析
    MySQL查看和修改表的存储引擎
    mysql备份和还原
  • 原文地址:https://www.cnblogs.com/acceptedzhs/p/cf-705-solution.html
Copyright © 2020-2023  润新知