Codeforces Round #713 (Div. 3)(A~G)(埃氏筛,dp)

A. Spy Detected!

找到只有1个的数就行

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string>
#include<map>
#include<sstream>
#define MAXN 50005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n; 
int a[105],vis[105];
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        memset(vis,0,sizeof(vis));
        int temp1=0,temp2=0,ans=0,cnt=0;;
        int flag=0;
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            vis[a[i]]++;
            if(vis[a[i]]==1){
                if(!temp1)
                    temp1=i+1;
                else if(!temp2)
                    temp2=i+1;
            }else if(vis[a[i]]>1&&!flag){
                if(!temp2){
                    flag=2;
                }else if(a[i]==a[temp1-1]){
                    flag=2;
                }else if(a[i]==a[temp2-1]){
                    flag=1;
                }
            }
        }
        if(flag==1)
            printf("%d\n",temp1);
        else{
            printf("%d\n",temp2);
        }
    }
    return 0;
}

B. Almost Rectangle

根据给定的两个*的位置构造矩形即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string>
#include<map>
#include<sstream>
#define MAXN 50005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n; 
char m[405][405];
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%s",m[i]+1);
        int tempx1=0,tempx2=0,tempy1,tempy2;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(m[i][j]=='*'){
                    if(!tempx1){
                        tempx1=i,tempy1=j;
                    }else{
                        tempx2=i,tempy2=j;
                    }
                }
        if(tempx1!=tempx2&&tempy1!=tempy2){
            m[tempx1][tempy2]='*';
            m[tempx2][tempy1]='*';
        }else if(tempx1==tempx2){
            if(tempx1!=n){
                m[tempx1+1][tempy1]='*';
                m[tempx1+1][tempy2]='*';
            }else{
                m[tempx1-1][tempy1]='*';
                m[tempx1-1][tempy2]='*';
            }    
        }else if(tempy1==tempy2){
            if(tempy1!=n){
                m[tempx1][tempy1+1]='*';
                m[tempx2][tempy2+1]='*';
            }else{
                m[tempx1][tempy1-1]='*';
                m[tempx2][tempy2-1]='*';
            }
        }
        for(int i=1;i<=n;i++)
            printf("%s\n",m[i]+1);
    }
    return 0;
}

C. A-B Palindrome

先判断能否构成,再根据0和1的数量和?的对应关系判断即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string>
#include<map>
#include<sstream>
#define MAXN 200005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n,a,b; 
char m[MAXN];
int pos[MAXN];
int judge(){
    for(int i=0;i<n/2;i++){
        if(m[i]!=m[n-1-i]&&m[i]!='?'&&m[n-1-i]!='?'){
            return 0;
        }
    }
    return 1;
}
int main(){
    scanf("%d",&t);
    while(t--){
        memset(m,0,sizeof(m));
        memset(pos,0,sizeof(pos)); 
        scanf("%d%d",&a,&b);//a个0,b个1
        n=a+b;
        scanf("%s",m);
        if(((a&1)&&(b&1))||!judge()){//先判断原来能不能构成回文串 
            printf("-1\n");
        }else if(n==1&&(a+b)==1&&m[0]=='?'){//特判只有一个?的请况 
            if(a)
                printf("0\n");
            else if(b)
                printf("1\n");
        }else{
            int cnt=0;
            for(int i=0;i<n/2;i++){
                if(m[i]=='?'&&m[n-1-i]=='?'){
                    pos[cnt++]=i;
                }else if(m[i]=='?'){
                    m[i]=m[n-i-1];
                    if(m[i]=='0')
                        a-=2;
                    else
                        b-=2;
                }else if(m[n-i-1]=='?'){
                    m[n-i-1]=m[i];
                    if(m[i]=='0')
                        a-=2;
                    else
                        b-=2;
                }else{
                    if(m[i]=='0')
                        a-=2;
                    else
                        b-=2;
                }
            }
            int dan=0;
            if(n&1){
                if(m[n/2]=='1'){
                    b--;
                }else if(m[n/2]=='0')
                    a--;
                else if(m[n/2]=='?')
                    dan=n/2;
            }
            if(!a&&!b&&!dan&&!cnt){//如果全部构造完了 
                if(a==0&&b==0)
                    printf("%s\n",m);
                else
                    printf("-1\n");
            }else if((a+b)!=2*cnt+(dan>0?1:0)){
                printf("-1\n");
            }else{
                if(dan==0){
                    if((a&1)||(b&1)){
                        printf("-1\n");
                        continue;;
                    }
                    for(int i=0;i<cnt;i++){
                        if(a){
                            m[pos[i]]=m[n-pos[i]-1]='0';
                            a-=2;
                        }else{
                            m[pos[i]]=m[n-pos[i]-1]='1';
                            b-=2;
                        }
                    }
                    if(a==0&&b==0)
                        printf("%s\n",m);
                    else 
                        printf("-1\n");
                }else{
                    if(a&1){
                        m[n/2]='0';
                        --a;
                    }else if(b&1){
                        m[n/2]='1';
                        --b;
                    }
                    if((a&1)||(b&1)){
                        printf("-1\n");
                        continue;
                    }else{
                        for(int i=0;i<cnt;i++){
                            if(a){
                                m[pos[i]]=m[n-pos[i]-1]='0';
                                a-=2;
                            }else{
                                m[pos[i]]=m[n-pos[i]-1]='1';
                                b-=2;
                            }
                        }
                        if(a==0&&b==0)
                            printf("%s\n",m);
                        else 
                            printf("-1\n");
                    }
                }
            }
        }
    }
    return 0;
}

D. Corrupted Array

先计算出所有数的总和。再判断是总和减去一个数后是否为数列中某个数的两倍。如果是的话则该数为加上的数,额外的数为减去的那个数

需要特别注意的是需要判断减去的那个数是不是该数。若是的话则需要判断该数出现了几次

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string>
#include<map>
#include<unordered_map>
#include<sstream>
#define MAXN 200005
#define MAXM 1000000005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n;
ll s; 
ll b[MAXN];
unordered_map<ll,int>vis;
int main(){
    scanf("%d",&t);
    while(t--){
        vis.clear();
        memset(b,0,sizeof(b));
        s=0;
        scanf("%d",&n);
        for(register int i=0;i<n+2;++i){
            scanf("%lld",&b[i]);
            ++vis[b[i]];
            s+=b[i];
        }
        int flag=0,ans;
        ll temp;
        for(register int i=0;i<n+2;++i){
            temp=s-b[i];
            if(temp&1)
                continue;
            else
                temp/=2;
            if(temp<MAXM){
                if(vis[temp]&&temp!=b[i]){//如果减去的不是temp,且temp出现过 
                    flag=1;
                    ans=i;
                    break;
                }else if(vis[temp]>1&&temp==b[i]){//如果减去的是temp且temp出现了不止一次 
                    flag=1;
                    ans=i;
                    break;
                }
            }
        }
        if(!flag)
            printf("-1\n");
        else{
            for(register int i=0;i<ans;++i){
                if(b[i]==temp&&flag){
                    flag=0;
                    continue;
                }
                printf("%lld ",b[i]);
            }
            for(register int i=ans+1;i<n+2;++i){
                if(b[i]==temp&&flag){
                    flag=0;
                    continue;
                }
                printf("%lld ",b[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

E. Permutation by Sum

先计算l~r中能存的数的数目cnt。

那么min=1+……+cnt,max=n-cnt+1+……n。

如果s在min和max之间,那么则可以构造出一个l~r的序列的和为s。

接下来构造即可。剩余位置随便填

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string>
#include<map>
#include<unordered_map>
#include<sstream>
#define MAXN 200005
#define MAXM 1000000005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n,l,r,s;
int vis[505],ans[505];
//unordered_map<ll,int>vis;
int main(){
    scanf("%d",&t);
    while(t--){
        memset(vis,0,sizeof(vis));
        memset(ans,0,sizeof(ans));
        scanf("%d%d%d%d",&n,&l,&r,&s);
        int cnt=r-l+1;
        int minn=(1+cnt)*cnt/2,maxn=(n+n-cnt+1)*cnt/2;
        if(s<minn||s>maxn){
            printf("-1\n");
        }else{
            int cha=s-minn;
            int temp=cha/cnt;
            int min_ind=cnt,max_ind=n+1,mid_val=n+1;
            while(1){
                if(max_ind-min_ind-1>=cha){
                    mid_val=min_ind+cha;
                    min_ind--;
                    break;
                }else{
                    min_ind--;
                    max_ind--;
                    cha-=(max_ind-min_ind-1);
                }
            }
            cnt=l;
            for(int i=1;i<=min_ind;++i){
                vis[i]=1;
                ans[cnt]=i;
                ++cnt;
            }
            if(mid_val!=n+1){
                vis[mid_val]=1;
                ans[cnt]=mid_val;
                ++cnt;
            }
            for(int i=max_ind;i<=n;++i){
                vis[i]=1;
                ans[cnt]=i;
                ++cnt;
            }
            cnt=1;
            for(int i=1;i<l;i++){
                while(vis[cnt])
                    ++cnt;
                vis[cnt]=1;
                ans[i]=cnt;
                ++cnt;
            }
            for(int i=r+1;i<=n;i++){
                while(vis[cnt])
                    ++cnt;
                vis[cnt]=1;
                ans[i]=cnt;
                ++cnt;    
            }
            for(int i=1;i<=n;i++)
                printf("%d ",ans[i]);
            printf("\n");
        }
    }
    return 0;
}

F. Education

如果我们要到一个岗位上工作到买电脑,那么则越早到那个岗位越好。(因为工资必定会增加)

所以我们记录每个一直在每个岗位上工作直到买到电脑的日期即可。

求出最短的那个即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string>
#include<map>
#include<unordered_map>
#include<sstream>
#define MAXN 200005
#define MAXM 1000000005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n,c;
int a[MAXN],b[MAXN];//ans表示答案,sav表示到下一个岗位的存款,d表示天数 
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&c);
        for(register int i=0;i<n;++i)
            scanf("%d",&a[i]);
        for(register int i=0;i<n-1;++i)
            scanf("%d",&b[i]);
        b[n-1]=0;
        ll sav=0,cur=0,ans=1e18;
        for(register int i=0;i<n;++i){
            ans=min(ans,cur+max(0ll,c-sav+a[i]-1)/a[i]);
            ll ex=max(0ll,b[i]-sav+a[i]-1)/a[i];//为了到达这个职位需要存多少天的钱 
            cur+=ex+1;//加上到达职位的天数 
            sav+=a[i]*ex-b[i];//剩余存款 
        } 
        printf("%lld\n",ans);
    }
    return 0;
}

G. Short Task

预处理每个数的因子和即可。

可以用埃氏筛计算出该数的一个因子。

如果该数为质数,则d[i]=i+1.

如果不为质数,则先计算出这个因子所带来的影响,并且将这个因子除出这个数,

并且运用:d(ab)=d(a)d(b) if gcd(a,b)=1.来加速运算。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string>
#include<map>
#include<unordered_map>
#include<sstream>
#define MAXN 10000005
#define MAXM 1000000005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int t,n,c;
int d[MAXN],s[MAXN],ans[MAXN];//ans表示答案,sav表示到下一个岗位的存款,d表示天数 
int main(){
    d[1]=1;
    for(register int i=2;i*i<MAXN;++i){
        if(!d[i]){
            d[i]=i;
            for(register int j=i*i;j<MAXN;j+=i)
                if(!d[j])
                    d[j]=i;//存该数的最小因子 
        }
    }
    s[1]=1;
    for(register int i=2;i<MAXN;++i){
        if(!d[i]){
            d[i]=i;
            s[i]=i+1;
        }else{
            int j=i;
            s[i]=1;
            while(j%d[i]==0){
                j/=d[i];
                s[i]=s[i]*d[i]+1;//相当于加上这个因子的所有幂次 
            }
            s[i]*=s[j];//i和j互质。且j小于i,所以s[j]之前肯定被计算过了 
        }
    }
    memset(ans,-1,sizeof(ans));
    for(register int i=MAXN-1;i>0;--i)
        if(s[i]<MAXN)
            ans[s[i]] =i;//ans为s【i】的逆数组 
    scanf("%d",&t);
    while(t--){
        int c;
        scanf("%d",&c);
        printf("%d\n",ans[c]);
    }
    return 0;
}

 

posted @ 2021-04-17 14:15  mikku  阅读(32)  评论(0)    收藏  举报