Codeforces Round #470 (rated, Div. 2, based on VK Cup 2018 Round 1)题解

A. Protect Sheep

只要wolf的四邻接格子中没有sheep,则肯定有办法放狗使得狼无法接触到羊,把所有空格替换成狗就行了。

#include 
using namespace std;
typedef long long ll;
const int maxn=505;
const int maxm=100005;
const int maxe=200005;
const int mod=1e9+7;
int n,m;
char ma[maxn][maxn];
int dx[4]={-1,0,0,1};
int dy[4]={0,-1,1,0};
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;iscanf("%s",ma[i]);
    }
    bool f=1;
    for(int i=0;ifor(int j=0;jif(ma[i][j]=='W'){
                for(int k=0;k<4;k++){
                    int nx=i+dx[k];
                    int ny=j+dy[k];
                    if(nx<0||nx>=n)continue;
                    if(ny<0||ny>=m)continue;
                    if(ma[nx][ny]=='S'){f=0;break;}
                }
            }
            if(f==0)break;
        }
        if(f==0)break;
    }
    if(f==0){printf("No\n");return 0;}
    printf("Yes\n");
    for(int i=0;ifor(int j=0;jif(ma[i][j]=='.')ma[i][j]='D';
        }
    }
    for(int i=0;iprintf("%s\n",ma[i]);
    }
    return 0;
}

B. Primal Sport

首先处理处所有质数。
思路是先找出每个数作为X1的情况下,X0的最小值是多少,然后对于x2遍历它的每个素因子,确定x1的取值范围,然后就遍历那个取值范围找出答案最小值。

1.确定每个x1对应的x0最小值的方法就是:用每个质数去更新它的倍数a=k*prime(k>=2),x0[a]=min(x0[a],prime*(k-1)+1)

2.最终确定的x1的取值范围肯定是一段连续的区间(k to n),确定范围的方法类似(1)

#include 
using namespace std;
typedef long long ll;
const int maxn=1000005;
const int maxm=100005;
const int maxe=200005;
const int mod=1e9+7;
int n,m;
int prime[maxn];
int tot;
bool vis[maxn];
void init(){
    tot=0;
    for(int i=2;iif(vis[i])continue;
        prime[tot++]=i;
        for(int j=2;j*i<=maxn;j++){
            vis[j*i]=1;
        }
    }
}

int pre[maxn];

int main(){
    init();
    scanf("%d",&n);
    memset(pre,0x3f,sizeof(pre));
    for(int i=0;iint num=prime[i];
        for(int j=2;j*num<=n;j++){
            pre[j*num]=min(pre[j*num],(j-1)*num+1);
        }
    }
    int ans=0x3f3f3f3f;
    int cnt=n;
    for(int i=tot-1;i>=0;i--){
        if(prime[i]>=n)continue;
        if(n%prime[i])continue;
        int pos=((n/prime[i])-1)*prime[i]+1;
        while(cnt>=pos){
            ans=min(ans,pre[cnt]);
            cnt--;
        }
    }
    printf("%d\n",ans);
    return 0;
}

C. Producing Snow

考虑每天新增雪对后面每一天的融化数量的贡献,发现第i天的雪在第k天融化完,则它对第i到k-1天的贡献都是t[j],对第k天的贡献就是剩余的雪的数量。

所以二分雪到第几天刚好融化完,然后用类似前缀和的方式对区间打标记处理一下即可。

#include 
using namespace std;
typedef long long ll;
const int maxn=101005;
const int maxm=100005;
const int maxe=200005;
const int mod=1e9+7;
int n,m;
ll v[maxn];
ll t[maxn];
ll sum[maxn];
ll a[maxn];
ll ans[maxn];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&v[i]);
    for(int i=1;i<=n;i++)scanf("%lld",&t[i]);
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+t[i];
    }
    for(int i=1;i<=n;i++){
        int pos=lower_bound(sum+i,sum+n+1,v[i]+sum[i-1])-sum;
        ans[pos]+=v[i]+sum[i-1]-sum[pos-1];
        a[i]++;
        a[pos]--;
    }
    for(int i=1;i<=n;i++){
        a[i]+=a[i-1];
        ans[i]+=a[i]*t[i];
    }
    for(int i=1;i<=n;i++){
        printf("%lld ",ans[i]);
    }
    return 0;
}

D. Perfect Security

暴力一点就是n方的,肯定超时的做法。
异或就可以按位考虑,每个数想要异或之后变得更小,肯定是异或一个二进制位最为相似且不同位尽量少且尽量在低位的,所以建棵字典树用来查询即可,把每个数字变成一个三十位的二进制字符串插入到trie上就行了,涉及到删除操作开一个计数数组即可。

#include 
using namespace std;
typedef long long ll;
#define MP make_pair
const int maxn=300005;
const int maxm=(1<<25);
int n,m;
int a[maxn],p[maxn];
int ch[maxm][2];
int cou[maxm];
int sz;
void inser(int num){
    int u=0;
    for(int i=30;i>=0;i--){
        int c=0;
        if((1<1;
        if(!ch[u][c]){
            ch[sz][0]=ch[sz][1]=0;
            cou[sz]=0;
            ch[u][c]=sz++;
        }
        cou[u]++;
        u=ch[u][c];
    }
    cou[u]++;
}

void build(){
    for(int i=0;iint cal(int num){
    int num1=num;
    int u=0;
    for(int i=30;i>=0;i--){
        int c=0;
        if((1<1;
        if(!ch[u][c]||!cou[ch[u][c]]){
            c=1-c;
        }
        num1^=(c<return num1;
}

int main(){
    scanf("%d",&n);
    for(int i=0;iscanf("%d",&a[i]);
    for(int i=0;iscanf("%d",&p[i]);
    sz=1;
    memset(ch[0],0,sizeof(ch[0]));
    build();
    for(int i=0;iprintf("%d ",cal(a[i]));
    }
    return 0;
}

E. Picking Strings

推一推几个式子就可以发现:
B可以变成C,所以两串中的C都当成B来看。
任何B之前可以添加任意数量的A,所以对于查询区间非末尾的A都可以无视掉。
B的数量自能增加不能减少,且只能偶数倍的增加
区间末尾的A只能直接减少三个或者一个A变成两个B或者两个A变成两个B。

所以统计一下B数量的前缀和和A的后缀长度,然后分类讨论一下就可以了。

#include 
using namespace std;
typedef long long ll;
#define MP make_pair
const int maxn=100005;
const int maxm=(1<<25);
int n,m;
char s[maxn],t[maxn];
int bn1[maxn],bn2[maxn];
int an1[maxn],an2[maxn];
int a,b,c,d;
int main(){
    scanf("%s%s",s+1,t+1);
    n=strlen(s+1),m=strlen(t+1);
    for(int i=1;i<=n;i++){
        bn1[i]+=bn1[i-1]+(s[i]!='A'?1:0);
        if(s[i]!='A')continue;
        an1[i]=1+an1[i-1];
    }
    for(int i=1;i<=m;i++){
        bn2[i]+=bn2[i-1]+(t[i]!='A'?1:0);
        if(t[i]!='A')continue;
        an2[i]=1+an2[i-1];
    }
    int Q;
    scanf("%d",&Q);
    while(Q--){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        int b1num=bn1[b]-bn1[a-1];
        int a1num=min(b-a+1,an1[b]);
        int b2num=bn2[d]-bn2[c-1];
        int a2num=min(d-c+1,an2[d]);
        if(b1num>b2num){putchar('0');continue;}
        if(b1num==b2num){
            if(a1numputchar('0');continue;}
            int cha=a1num-a2num;
            if(cha%3){putchar('0');}
            else putchar('1');
            continue;
        }
        if(b1num==0){
            if(b2num%2){putchar('0');continue;}
            if(a1num<=a2num){putchar('0');continue;}
            int lef=(a1num-a2num)%3;
            if(lef>b2num){putchar('0');continue;}
            putchar('1');
            continue;
        }
        if(b1numint cha=b2num-b1num;
            if(cha%2){putchar('0');continue;}
            if(a1numputchar('0');continue;}
            int lef=(a1num-a2num)%3;
            if(b1num+lef>b2num){putchar('0');continue;}
            putchar('1');
            continue;
        }
    }
    return 0;
}

你可能感兴趣的:(codeforces)