TJUACM假期集训个人赛(九)(cf1453a-d cf1440a-c)

今天最后一场个人赛 出题玩抽象的 密码是 l a s t d a n c e lastdance lastdance 然后题名连起来是个人赛的最后一舞
在这里插入图片描述
最抽象的我觉得还是一套题出三道大模拟,人写没了
在这里插入图片描述
寻思最后一场好好打拿个 r k 1 rk1 rk1,最后十分钟被超了,三周个人赛没拿个 r k 1 rk1 rk1算是个小遗憾吧在这里插入图片描述

A. Cancel the Trains

题面
签到题 找到两侧同时开出的火车即可,输出相同的个数

#include <bits/stdc++.h>
#define N 200200
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}

int n,m,x,ans,cnt;
int t;
int main(){
    read(t);
    while(t--){
        set<int> s;
        ans=0;
        read(n),read(m);
        for(int i=1;i<=n;i++)read(x),s.insert(x);
        for(int i=1;i<=m;i++){
            read(x);
            if(s.find(x)!=s.end())ans++;
        }
        cout<<ans<<endl;
    }
}

B. Suffix Operations

题面
显然操作 2 2 2的贡献之和是每相邻两个数的差的绝对值,枚举遍历操作 1 1 1贡献最小的即可

#include <bits/stdc++.h>
#define N 1000100
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(ll &x){
    ll s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
bool cmp(ll x, ll b){
    return x>b;
}
ll n,k,now,ans,t,a[N];
char s[N];
int main(){
    read(t);
    while(t--){
        ans=now=0;
        read(n);
        for(int i=1;i<=n;i++)read(a[i]);
        for(int i=2;i<=n;i++)ans+=abs(a[i]-a[i-1]);
        for(int i=2;i<n;i++)now=max(now,abs(a[i]-a[i-1])+abs(a[i+1]-a[i])-abs(a[i+1]-a[i-1]));
        now=max(now,abs(a[2]-a[1]));now=max(now,abs(a[n]-a[n-1]));
        cout<<ans-now<<endl;
    }
}

C. Triangles

题面
大模拟一,把答案分为两种,一种是有底边构造高,一种是有高构造底边。

每次枚举一列或者一行的 0 − 9 0-9 09,如果只出现两次,那就更新两次答案:先以这两个为边,构造两侧最远的高。再以这两个中的一个构造底边,枚举两侧的高更新答案。

输入时维护最上面最下面最左边最右边的 0 − 9 0-9 09的行列数即可。
时间复杂度 O ( n 2 ) O(n^2) O(n2)

#include <bits/stdc++.h>
#define N 2020
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
bool cmp(int x, int b){
    return x>b;
}
int n,sqr[N][N],t,le[15],ri[15],up[15],dn[15],ans[15],now[15][2],vis[15];
int main(){
    read(t);
    while(t--){
        for(int i=0;i<=9;i++)le[i]=ri[i]=up[i]=dn[i]=ans[i]=vis[i]=0;
        read(n);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                char chr=getchar();
                while(chr<'0'||chr>'9')chr=getchar();
                sqr[i][j]=chr&15;
                if(!le[sqr[i][j]]||j<le[sqr[i][j]])le[sqr[i][j]]=j;
                if(ri[sqr[i][j]]<j)ri[sqr[i][j]]=j;
                if(!up[sqr[i][j]]||i<up[sqr[i][j]])up[sqr[i][j]]=i;
                if(dn[sqr[i][j]]<i)dn[sqr[i][j]]=i;
                vis[sqr[i][j]]++;
            }
        }
        for(int j=1;j<=n;j++){
            for(int i=0;i<=9;i++)now[i][0]=now[i][1]=0;
            for(int i=1;i<=n;i++){
                if(!now[sqr[i][j]][0])now[sqr[i][j]][0]=now[sqr[i][j]][1]=i;
                else now[sqr[i][j]][1]=i;
            }
            for(int i=0;i<=9;i++){
                if(now[i][1]==now[i][0]&&now[i][0]==0)continue;
                int len=now[i][1]-now[i][0];
                if(now[i][1]==now[i][0]){
                    len=max(now[i][1]-1,n-now[i][0]);
                    ans[i]=max(ans[i],max((j-le[i])*(len),(ri[i]-j)*(len)));
                }
                else{
                    ans[i]=max(ans[i],max((j-1)*(len),(n-j)*(len)));
                    len=max(now[i][1]-1,n-now[i][0]);
                    ans[i]=max(ans[i],max((j-le[i])*(len),(ri[i]-j)*(len)));
                }
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=0;j<=9;j++)now[j][0]=now[j][1]=0;
            for(int j=1;j<=n;j++){
                if(!now[sqr[i][j]][0])now[sqr[i][j]][0]=now[sqr[i][j]][1]=j;
                else now[sqr[i][j]][1]=j;
            }
            for(int j=0;j<=9;j++){
                if(now[j][1]==now[j][0]&&now[j][0]==0)continue;
                int len=now[j][1]-now[j][0];
                if(now[j][1]==now[j][0]){
                    len=max(now[j][1]-1,n-now[j][0]);
                    ans[j]=max(ans[j],max((i-up[j])*(len),(dn[j]-i)*(len)));
                }
                else{
                    ans[j]=max(ans[j],max((i-1)*(len),(n-i)*(len)));
                    len=max(now[j][1]-1,n-now[j][0]);
                    ans[j]=max(ans[j],max((i-up[j])*(len),(dn[j]-i)*(len)));
                }
            }
        }
        for(int i=0;i<=9;i++){
            if(vis[i]>1)printf("%d",ans[i]);
            else putchar('0');
            if(i==9)putchar('\n');
            else putchar(' ');
        }
    }
}
/*
1
8
42987101
98289412
38949562
87599023
92834718
83917348
19823743
38947912
*/

D. Checkpoints

题面
改第三个大模拟时间太久了 这题没时间做了 就是一道简单的数学题

首先一个 1 1 1的期望是 2 2 2,这个看样例就能看出来,推一下就是

E =               1 × 1 2 + 2 × 1 4 + . . . + n × 1 2 n E=\,\,\,\,\,\,\,\,\,\,\,\,\,1\times\frac{1}{2}+2\times\frac{1}{4}+...+n\times\frac{1}{2^n} E=1×21+2×41+...+n×2n1
2 E = 1 + 2 × 1 2 + 3 × 1 4 + . . . + n × 1 2 n − 1 2E=1+2\times\frac{1}{2}+3\times\frac{1}{4}+...+n\times\frac{1}{2^{n-1}} 2E=1+2×21+3×41+...+n×2n11
下面减上面得 E = 1 + 1 2 + 1 4 + . . . + 1 2 n − 1 − 1 2 n , n → + ∞ E=1+\frac{1}{2}+\frac{1}{4}+...+\frac{1}{2^{n-1}}-\frac{1}{2^n},n\rightarrow+\infty E=1+21+41+...+2n112n1,n+ E = 2 E=2 E=2

对于 1 1 1后面跟着 n n n 0 0 0,假设现在已经走到了第 K K K 0 0 0,设当前期望为 E k E_k Ek,则有

E k + 1 =                                 ( E k + 1 ) × 1 2 + 2 ( E k + 1 ) × 1 4 + . . . + n ( E k + 1 ) × 1 2 n E_{k+1}=\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,(E_k+1)\times\frac{1}{2}+2(E_k+1)\times\frac{1}{4}+...+n(E_k+1)\times\frac{1}{2^n} Ek+1=(Ek+1)×21+2(Ek+1)×41+...+n(Ek+1)×2n1
2 E k + 1 = ( E k + 1 ) + 2 ( E k + 1 ) × 1 2 + 3 ( E k + 1 ) × 1 4 + . . . + n ( E k + 1 ) × 1 2 n − 1 2E_{k+1}=(E_k+1)+2(E_k+1)\times\frac{1}{2}+3(E_k+1)\times\frac{1}{4}+...+n(E_k+1)\times\frac{1}{2^{n-1}} 2Ek+1=(Ek+1)+2(Ek+1)×21+3(Ek+1)×41+...+n(Ek+1)×2n11

下面减上面得 E k + 1 = ( E k + 1 ) × ( 1 + 1 2 + 1 4 + . . . + 1 2 n − 1 − 1 2 n ) , n → + ∞ E_{k+1}=(E_k+1)\times(1+\frac{1}{2}+\frac{1}{4}+...+\frac{1}{2^{n-1}}-\frac{1}{2^n}),n\rightarrow+\infty Ek+1=(Ek+1)×(1+21+41+...+2n112n1),n+ E k + 1 = 2 ( E k + 1 ) E_{k+1}=2(E_k+1) Ek+1=2(Ek+1)

推出通项公式有 E k = 2 k + 2 − 2 E_k=2^{k+2}-2 Ek=2k+22

因此我们知道了一段 100...0 100...0 100...0的期望,由于期望之间是线性关系,因此我们只需从大到小枚举 E k E_k Ek即可。

#include <bits/stdc++.h>
#define N 2020
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(ll &x){
    ll s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
int n,m,cnt[N],now;
ll t,x,frac[100];
int main(){
    read(t);
    frac[0]=2;
    for(int i=1;i<=61;i++)frac[i]=frac[i-1]+1<<1;
    while(t--){
        read(x);
        now=0;
        if(x&1){
            puts("-1");
            continue;
        }
        for(int i=61;~i;i--){
            while(x>=frac[i]){
                cnt[++now]=1,x-=frac[i];
                for(int j=1;j<=i;j++)cnt[++now]=0;
            }
        }
        printf("%d\n",now);
        for(int i=1;i<=now;i++)printf("%d ",cnt[i]);
        puts("");
    }
}

A. Buy the String

题面
输入一个字符串,在每一位判断一下换更优还是不换更优即可

#include <bits/stdc++.h>
#define N 2002
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}

int n,x,y,m,ans,t;
char s[N];
int main(){
    read(t);
    while(t--){
        read(n),read(x),read(y),read(m);
        scanf("%s",s);
        ans=0;
        for(int i=0;i<n;i++){
            if(s[i]=='0')ans+=min(x,y+m);
            else ans+=min(y,x+m);
        }
        cout<<ans<<endl;
    }
}

B. Sum of Medians

题面
p = ⌈ n 2 ⌉ p=\lceil\frac{n}{2}\rceil p=2n,为什么要设呢,因为方便我打字,那个公式要打好久
求每一段第 p p p大的数和最大,我们利用贪心的思想,先将数组从大到小排序,先将数组的前 p p p大的数分给第一段,然后将后 n − p + 1 n-p+1 np+1小的分给第一段,以此类推,最终答案就是第 p , 2 p , . . . , k p p,2p,...,kp p,2p,...,kp大的数之和。

#include <bits/stdc++.h>
#define N 1000100
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(ll &x){
    ll s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
bool cmp(ll x, ll b){
    return x>b;
}
ll n,k,now,ans,t,a[N];
char s[N];
int main(){
    read(t);
    while(t--){
        ans=0;
        read(n),read(k);
        for(int i=1;i<=n*k;i++)read(a[i]);
        sort(a+1,a+1+n*k,cmp);
        if(n&1)now=(n+1)/2;
        else now=n/2;
        now=n-now+1;
        for(int i=1;i<=k;i++){
            ans+=a[i*now];
        }
        cout<<ans<<endl;
    }
}

C1. Binary Table (Easy Version)

题面
大模拟二:小模拟,没寻思后面是个一样的模拟,早知道直接做后面那个题了

操作是在一个 2 × 2 2\times2 2×2的小方格中取三个数将 0 0 0 1 1 1 1 1 1 0 0 0,我们设这个操作中没变的那个方格为中心方格。
一个性质就是在 2 × 2 2\times2 2×2的小方格中,以其他三个为中心方格做操作,会只改变该方格中一个块的数。所以用这个性质,每见到一个 1 1 1就这样做三次操作即可。题目要求的操作数少于 3 n m 3nm 3nm,边界条件的 3 3 3就是这么来的。
模拟即可

#include <bits/stdc++.h>
#define N 2020
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
bool cmp(int x, int b){
    return x>b;
}
int n,m,sqr[N][N],t,cnt;
int main(){
    read(t);
    while(t--){
        read(n);read(m);
        cnt=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                char chr=getchar();
                while(chr<'0'||chr>'9')chr=getchar();
                sqr[i][j]=chr&15;
                if(sqr[i][j])cnt+=3;
            }
        }
        printf("%d\n",cnt);
        for(int i=1;i<n;i++){
            for(int j=1;j<m;j++){
                if(sqr[i][j]==1){
                    printf("%d %d %d %d %d %d\n",i,j,i,j+1,i+1,j+1);
                    printf("%d %d %d %d %d %d\n",i,j,i,j+1,i+1,j);
                    printf("%d %d %d %d %d %d\n",i,j,i+1,j,i+1,j+1);
                    sqr[i][j]=0;
                }
            }
        }
        for(int j=1;j<m;j++){
            if(sqr[n][j]==1){
                printf("%d %d %d %d %d %d\n",n,j,n,j+1,n-1,j+1);
                printf("%d %d %d %d %d %d\n",n,j,n-1,j,n-1,j+1);
                printf("%d %d %d %d %d %d\n",n,j,n,j+1,n-1,j);
                sqr[n][j]=0;
            }
        }
        for(int i=1;i<n;i++){
            if(sqr[i][m]==1){
                printf("%d %d %d %d %d %d\n",i,m,i+1,m-1,i+1,m);
                printf("%d %d %d %d %d %d\n",i,m,i,m-1,i+1,m);
                printf("%d %d %d %d %d %d\n",i,m,i+1,m-1,i,m-1);
                sqr[i][m]=0;
            }
        }
        if(sqr[n][m]==1){
            printf("%d %d %d %d %d %d\n",n,m,n-1,m,n,m-1);
            printf("%d %d %d %d %d %d\n",n,m,n-1,m-1,n,m-1);
            printf("%d %d %d %d %d %d\n",n,m,n-1,m,n-1,m-1);
            sqr[n][m]=0;
        }
    }
}

C2. Binary Table (Hard Version)

题面
难版本的,我们考虑递推操作每碰到一个 1 1 1就把这个 1 1 1和下面两个数操作,这样如果不考虑下面的情况,最多 O ( n m ) O(nm) O(nm)就可以处理掉所有的 1 1 1,但是显然不能都这么做,因为最后两行要一起处理掉,所以我们先用上面的方法处理掉剩两行的情况,再单独处理最后两行。

最后两行我们从左往右按列递推,如果该列两个都为 1 1 1那就直接操作这两个和右边随便一个,如果有一个为 1 1 1就操作这个 1 1 1和右边两个,这样用 m m m次就可以操作 2 m 2m 2m个数,直到最后一个 2 × 2 2\times 2 2×2个小方格。 我们暴力解决这个小方格即可。因为要先输出操作数再输出操作,我也没想到我这一系列操作有什么方法可以先算出操作数,我就直接模拟两次了。

#include <bits/stdc++.h>
#define N 2020
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
bool cmp(int x, int b){
    return x>b;
}
int n,m,sqr[N][N],a[N][N],t,cnt,now;
void print(int aa, int b, int c, int d, int ee, int f){
    printf("%d %d %d %d %d %d\n",aa,b,c,d,ee,f);
    a[aa][b]^=1,a[c][d]^=1,a[ee][f]^=1;
}
int main(){
    read(t);
    while(t--){
        read(n);read(m);
        cnt=now=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                char chr=getchar();
                while(chr<'0'||chr>'9')chr=getchar();
                sqr[i][j]=a[i][j]=chr&15;
            }
        }
        for(int i=1;i<=n-2;i++){
            for(int j=1;j<m;j++){
                if(sqr[i][j]==1)cnt++,sqr[i][j]^=1,sqr[i+1][j]^=1,sqr[i+1][j+1]^=1;
            }
            if(sqr[i][m]==1)cnt++,sqr[i][m]^=1,sqr[i+1][m]^=1,sqr[i+1][m-1]^=1;
        }
        for(int j=1;j<=m-2;j++){
            if(!sqr[n-1][j]&&!sqr[n][j])continue;
            if(sqr[n-1][j]&&sqr[n][j]){
                cnt++;
                if(sqr[n][j+1])sqr[n][j+1]^=1,sqr[n-1][j]^=1,sqr[n][j]^=1;
                else sqr[n-1][j+1]^=1,sqr[n-1][j]^=1,sqr[n][j]^=1;
            }
            else if(sqr[n-1][j]&&!sqr[n][j])cnt++,sqr[n-1][j]^=1,sqr[n-1][j+1]^=1,sqr[n][j+1]^=1;
            else if(!sqr[n-1][j]&&sqr[n][j])cnt++,sqr[n][j]^=1,sqr[n-1][j+1]^=1,sqr[n][j+1]^=1;
        }
        for(int i=n-1;i<=n;i++){
            for(int j=m-1;j<=m;j++)now+=sqr[i][j];
        }
        if(now==4)cnt+=4;
        if(now==3)cnt++;
        if(now==2)cnt+=2;
        if(now==1)cnt+=3;
        cout<<cnt<<endl;
        for(int i=1;i<=n-2;i++){
            for(int j=1;j<m;j++){
                if(a[i][j]==1)print(i,j,i+1,j,i+1,j+1); 
            }
            if(a[i][m]==1)print(i,m,i+1,m,i+1,m-1);
        }
        for(int j=1;j<=m-2;j++){
            if(!a[n-1][j]&&!a[n][j])continue;
            if(a[n-1][j]&&a[n][j]){
                if(a[n][j+1])print(n,j+1,n-1,j,n,j);
                else print(n-1,j+1,n-1,j,n,j);
                continue;
            }
            else if(a[n-1][j]&&!a[n][j])print(n-1,j,n-1,j+1,n,j+1);
            else if(!a[n-1][j]&&a[n][j])print(n,j,n-1,j+1,n,j+1);
        }
        if(now==4){
            print(n-1,m,n,m-1,n,m);//n-1,m-1
            print(n-1,m-1,n,m-1,n,m);//n-1,m
            print(n-1,m-1,n-1,m,n,m);//n,m-1
            print(n-1,m-1,n-1,m,n,m-1);//n,m
        }
        if(now==3){
            if(!a[n-1][m-1])print(n-1,m,n,m-1,n,m);
            else if(!a[n-1][m])print(n-1,m-1,n,m-1,n,m);
            else if(!a[n][m-1])print(n-1,m-1,n-1,m,n,m);
            else if(!a[n][m])print(n-1,m-1,n-1,m,n,m-1);
        }
        if(now==2){
            if(a[n-1][m-1]&&a[n-1][m])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n,m-1,n,m);
            else if(!a[n-1][m-1]&&!a[n-1][m])print(n-1,m-1,n-1,m,n,m),print(n-1,m-1,n-1,m,n,m-1);
            else if(a[n-1][m-1]&&a[n][m])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m-1);
            else if(!a[n-1][m-1]&&!a[n][m])print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m);
            else if(a[n-1][m-1]&&a[n][m-1])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m);
            else if(!a[n-1][m-1]&&!a[n][m-1])print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m-1);
        }
        if(now==1){
            if(a[n-1][m-1])print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m),print(n-1,m-1,n-1,m,n,m-1);
            else if(a[n-1][m])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m),print(n-1,m-1,n-1,m,n,m-1);
            else if(a[n][m-1])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m-1);
            else if(a[n][m])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m);;
        }
        /*for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)printf("%d ",a[i][j]);
            puts("");
        }*/
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值