正题

      Portal

      又是掉分的一天,D题看漏一个“至少”,就一直卡在那里,然后最后就只做出来三题。

      赛后看了一眼EF,大概半个小时就做出来了。

      还是太菜了,要更细心一些,写篇Blog来记录一下。

    T1

      没什么好说的,直接把一个相邻两项不同的矩阵改一改就是答案。


#include<bits/stdc++.h> using namespace std; int T,n,m; int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&m);
        if((n*m)&1){
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++)
                    printf((i+j)&1?"W":"B");
                printf("\n");
            }
        }
        else{
            bool tf=false;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++)
                    if((i+j)&1){
                        if(!tf) printf("B"),tf=true;
                        else printf("W");
                    }
                    else printf("B");
                printf("\n");
            }
        }
    }
}

    T2

      题目已经告诉你只有-1,0,1了,那就很好做了,看看差值和前面是否有-1,1就可以了。

#include<bits/stdc++.h> using namespace std; const int N=100010; int T,n; int a[N],b[N]; int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) scanf("%d",&b[i]);
        int tf=0;
        bool ans=true;
        for(int i=1;i<=n;i++){
            if(b[i]==a[i] || (1<<(b[i]-a[i]>0))&tf);
            else {ans=false;break;}
            if(a[i]) tf|=(1<<(a[i]>0));
        }
        if(!ans) printf("NO\n");
        else printf("YES\n");
    }
}

    T3

      边循环边看一下以i结尾可行的最小开头是多少,用一个map就可以搞定。

#include<bits/stdc++.h> using namespace std; const int N=200010; int n; int a[N]; map<long long,int> mp; int main(){
    scanf("%d",&n);
    int x,mmax=-1;
    long long tot=0;
    long long ans=0;
    mp[0]=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        tot+=x;
        if(mp.find(tot)!=mp.end()) mmax=max(mp[tot],mmax);
        mp[tot]=i;
        ans+=i-mmax-1;
    }
    printf("%I64d",ans);
}

    T4

      是真的恶心,首先可以把L看成1,把R看成0,那么每一秒“至少”要让一对01反转。

      我们可以选择每一次反转一对,这样花费的秒数肯定最多。

      我们也可以选择贪心得每次反转可以反转的,这样秒数肯定最少(贪心证明考虑1不断向左走,先走一定不比后走差。

      前者可以O(n)算,后者的复杂度就是前者算出来的数。

      可不可行就判断k是否在此区间就可以了。

      若可行,那么我们前x秒贪心,x+1秒反转一定的数,后面k-x-1每秒一对。至于怎么写,就各有所好了。

#include<bits/stdc++.h> using namespace std; const int N=3010; int n,k; vector<int> ans[3000010]; bool a[N],b[N]; bool tf[3010]; int main(){
    scanf("%d %d",&n,&k);
    int tot=0,tmp,mmax=0,A=1;
    char ch[N];
    scanf("%s",ch+1);
    for(int i=1;i<=n;i++){
        a[i]=b[i]=(ch[i]=='L');
        if(!a[i]) {
            tot++;
            if(ch[i+1]=='L') ans[1].push_back(i),tf[i]=true;
        }
        else mmax+=tot;
    }
    while(ans[A].size()>0){
        for(int i=0;i<ans[A].size();i++) a[ans[A][i]]=1,a[ans[A][i]+1]=0,tf[ans[A][i]]=false;
        for(int i=0;i<ans[A].size();i++){
            if(ans[A][i]>1 && !a[ans[A][i]-1] && !tf[ans[A][i]-1]) ans[A+1].push_back(ans[A][i]-1);
            if(ans[A][i]<n-1 && a[ans[A][i]+2]) ans[A+1].push_back(ans[A][i]+1),tf[ans[A][i]+1]=true;
        }
        A++;
        if(A>k+1) break;
    }
    A--;
    if(A>k || mmax<k) printf("-1");
    else{
        int pos=1;
        while(pos<=A && mmax-ans[pos].size()>=k-pos){
            mmax-=ans[pos].size();
            printf("%d ",ans[pos].size());
            for(int i=0;i<ans[pos].size();i++) printf("%d ",ans[pos][i]),b[ans[pos][i]]=1,b[ans[pos][i]+1]=0;
            printf("\n");pos++;
        }
        if(pos==A+1) return 0;
        printf("%d ",mmax-k+pos);for(int i=0;i<mmax-k+pos;i++) printf("%d ",ans[pos][i]),b[ans[pos][i]]=1,b[ans[pos][i]+1]=0;printf("\n");
        for(int i=2;i<=n;i++) if(b[i]){
            int tmp=i;
            while(tmp>1 && !b[tmp-1]){
                b[tmp]=0;b[tmp-1]=1;tmp--;
                printf("1 %d\n",tmp);
            }
        }
    }
}

    T5

      这题也很容易想,首先如果我们可以构造出来一个三层的,那么更多层数的我们可以诱导它走完除最后三层外的所有格子并到达三层的起点。

      这个三层的矩阵可以手玩也可以暴力dfs(反正也就阶乘

      这里不给出。

      然后外层蛇形走位就可以到里面了。

#include<bits/stdc++.h> using namespace std; int n; int ans[510][510]; int main(){
    scanf("%d",&n);
    if(n<=2){printf("-1");return 0;}
    else{
        int tot=n*n,T=0;
        ans[1][1]=tot-1;ans[1][2]=tot-2;ans[1][3]=tot-3;
        ans[2][1]=tot-4;ans[2][2]=tot-8;ans[2][3]=tot-7;
        ans[3][1]=tot-5;ans[3][2]=tot;ans[3][3]=tot-6;
        for(int i=n;i>=5;i--){
            if(i&1){
                for(int j=1;j<=i;j++) ans[j][i]=++T;
                for(int j=i-1;j>=1;j--) ans[i][j]=++T;
            }
            else{
                for(int j=1;j<=i;j++) ans[i][j]=++T;
                for(int j=i-1;j>=1;j--) ans[j][i]=++T;
            }
        }
        if(n>=4){
            for(int j=1;j<=4;j++) ans[4][j]=++T;
            ans[3][4]=++T;ans[1][4]=++T;ans[2][4]=++T;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                printf("%d ",ans[i][j]);
            printf("\n");
        }
    }
}

    T6

      最后三题难度倒序。

      先考虑一个事实,假若我们选出来一个集合,将这个集合每一个元素的因子都放到一个权值数组上面,值>=2中最大那项的位置就是这个集合的答案。

      假设答案是x,我们考虑最多可以选到多少个数。

      显然就是要要求权值数组从x+1开始最多为1.

      首先前x个肯定可以选,考虑最多从后面选出多少个。

      先说结论,我们在后面选出真因子最大值<=x的数,这样显然是可行的。

      下面证明必要性。

      如果我们选出了一个真因子最大值>x的数a,那么它的>x的真因子中一定存在其真因子最大值<=x的b,而选了a就不能选b,而这样的b可能有很多个,所以选这些b不可能更劣。

      代码十分简单。

#include<bits/stdc++.h> using namespace std; const int N=500010; int mmax[N],n,t[N]; int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=i*2;j<=n;j+=i) mmax[j]=i;
    for(int i=1;i<=n;i++) t[mmax[i]]++;
    for(int i=1;i<=n;i++) for(int j=1;j<=t[i];j++) printf("%d ",i);
}