Codeforces Round #770(Div. 2)

A-Reverse and Concatenate

规定rev(s)操作能把字符串s反转,现有两种操作:1s变成s+rev(s)2s变成rev(s)+s。有t次询问,每次你有一个长度为n的字符串s,你能进行k次操作,问你能把原串变成多少种不同的串,输出答案。(1t100,1n100,0k1000)

思路

我们很容易能知道,进行一次操作就能得到一个回文串,而回文串进行的两种操作得到的答案相同,所以如果一开始就是回文串,答案就是1,如果不是,如果k0,则答案为1,否则,答案为2,就结束了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[1000005];
int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        int n,t;
        scanf("%d%d",&n,&t);
        scanf("%s",s+1);
        bool ck=1;
        for(int i=1;i<=n>>1;i++)if(s[i]!=s[n-i+1]){ck=0;break;}
        if(ck)printf("1\n");
        else
        {
            if(t==0)printf("1\n");
            else printf("2\n");
        }
    }
    return 0;
}

B-Fortune Telling

t次询问,每次有一个n,x,y,然后是n个非负数a1,a2,,an,对于每个数有两种操作:1x变成x+ai2x变成xai。问经过n次操作后,x还是x+3能变成y(1t104,1n105,0x109,0y1015,0ai109)

思路

蒟蒻不会,看了题解也只能勉强做出。首先我们要知道的是+运算和对数值奇偶性的改变是一样的,而且xx+3的奇偶性不同,而且xx+3中必有一个能变成y,因此问题就轻轻松松被解决了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        int n,x;
        ll y;
        scanf("%d%d%lld",&n,&x,&y);
        int num=0;
        int a;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a);
            if(a%2)num++;
        }
        if(x%2==y%2)
        {
            if(num%2)printf("Bob\n");
            else printf("Alice\n");
        }
        else
        {
            if(num%2)printf("Alice\n");
            else printf("Bob\n");
        }
    }
    return 0;
}

C-OKEA

t次询问,每次询问有一个n,k,输出的格式为“YES”加上nk1nk中的值(且每一项仅能输出一次)或“NO”。如果能够满足每一行中任意lr的平均值为一个整数,则输出前者,否则,输出后者。(1t500,1n,k100)

思路

显然我们可以知道k1时可以直接按顺序输出,同时我们也可以知道在其余情况中,n为奇数的情况一定为“NO”,偶数的情况一定为“YES”,且经过简单构造后就能直接AC啦。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        if(k==1)
        {
            printf("YES\n");
            for(int i=1;i<=n;i++)printf("%d\n",i);
        }
        else if(k>=2)
        {
            if(n%2)printf("NO\n");
            else
            {
                printf("YES\n");
                for(int i=1;i<=n>>1;i++)
                {
                    for(int j=k;j>=1;j--)
                    {
                        printf("%d ",i*2*k-2*j+1);
                    }
                    printf("\n");
                    for(int j=k;j>=1;j--)
                    {
                        printf("%d ",i*2*k-2*j+2);
                    }
                    printf("\n");
                }
            }
        }
    }
    return 0
}

E-Fair Share

m组数据,每组有n(n)个元素。现要求你将每组数据分成个数相等的两份放到可重集合LR中,问能否使得最后LR相等,若可以,输出“YES”,并输出每个元素的去向,否则,输出“NO”。(1m105,2n2105,1ai109)

思路

考虑二分图找欧拉回路,左部是m个点,右部是cnt个点,然后向左指代表到L集合,向右指代表到R集合中,然后就一直搜环就可以了。这里也附上Solemntee大佬的题解

代码

#include<bits/stdc++.h>
using namespace std;
vector<vector<int>>a(1e5+5),ans(1e5+5);
map<int,int>mp,num;
vector<vector<pair<int,int>>>v(4e5+5);
vector<int>cnt(4e5+5);
void dfs(int x,int dir)
{
    int n=x;
    cnt[n]--;
    while(cnt[n]>-1&&ans[min(n,v[n][cnt[n]].first)][v[n][cnt[n]].second]!=-1)cnt[n]--;
    if(cnt[n]==-1)return;
    ans[min(n,v[n][cnt[n]].first)][v[n][cnt[n]].second]=dir;
    dfs(v[n][cnt[n]].first,1-dir);
}
int main()
{
    int m;
    scanf("%d",&m);
    int tot=0;
    for(int i=1;i<=m;i++)
    {
        int n;
        scanf("%d",&n);
        a[i].resize(n+1);
        ans[i].resize(n+1,-1);
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
            if(!mp[a[i][j]])mp[a[i][j]]=++tot;
            num[mp[a[i][j]]]++;
        }
    }
    for(int i=1;i<=tot;i++)if(num[i]%2)
    {
        printf("NO\n");
        return 0;
    }
    int MAX=2e5;
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<a[i].size();j++)
        {
            v[i].push_back({mp[a[i][j]]+MAX,j});
            v[mp[a[i][j]]+MAX].push_back({i,j});
            cnt[i]++;
            cnt[mp[a[i][j]]+MAX]++;
        }
    }
    for(int i=1;i<=m;i++)dfs(i,0);
    printf("YES\n");
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<ans[i].size();j++)
        {
            if(ans[i][j])printf("L");
            else printf("R");
        }
        printf("\n");
    }
    return 0;
}

F-Fibonacci Additions

规定一个斐波那契加法:从lr,对al,al+1,...,ar分别加上F1,F2,...,Frl+1,并且对MOD进行取模,其中F1=1,F2=1,Fi=Fi1+Fi2。现在有两个同样长度的数组AB,有q次操作,每次选择其中一个数组,对于lr进行斐波那契加法。每次操作结束后,询问两数组是否相等。(1n,q3105,1MOD109+7)

思路

相比B题,这题就出的非常巧妙。首先要使AB相等,那么就可以构造一个C,使得Ci=AiBi。而要加的又是斐波那契数列,那么可以想到差分。再构造一个数组D,使得D1=C1,D2=C2C1,Di=CiCi1Ci2,那么就是在问D数组中有没有不是0的数字,而对AB进行斐波那契加法就能转换为Dl+1,Dr+1Frl+2,Dr+2Frl+1。这样问题就能被轻松解决了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[300005],b[300005];
ll c[300005],d[300005];
ll F[300005];
int main()
{
    int n,q;
    ll mod;
    scanf("%d%d%lld",&n,&q,&mod);
    F[1]=1;F[2]=1;
    for(int i=3;i<=n;i++)F[i]=(F[i-1]+F[i-2])%mod;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
    for(int i=1;i<=n;i++)c[i]=((a[i]-b[i])%mod+mod)%mod;
    d[1]=c[1];d[2]=((c[2]-c[1])%mod+mod)%mod;
    for(int i=3;i<=n;i++)
        d[i]=((c[i]-c[i-1]-c[i-2])%mod+mod)%mod;
    int num=0;
    for(int i=1;i<=n;i++)num+=(d[i]!=0);
    while(q--)
    {
        char s;
        int l,r;
        scanf("\n%c%d%d",&s,&l,&r);
        if(s=='A')
        {
            num-=(d[l]!=0);
            (d[l]+=1)%=mod;
            num+=(d[l]!=0);
            if(r+1<=n)
            {
                num-=(d[r+1]!=0);
                ((d[r+1]-=F[r-l+2])%=mod+mod)%=mod;
                num+=(d[r+1]!=0);
            }
            if(r+2<=n)
            {
                num-=(d[r+2]!=0);
                ((d[r+2]-=F[r-l+1])%=mod+mod)%=mod;
                num+=(d[r+2]!=0);
            }
        }
        else
        {
            num-=(d[l]!=0);
            ((d[l]-=1)%=mod+mod)%=mod;
            num+=(d[l]!=0);
            if(r+1<=n)
            {
                num-=(d[r+1]!=0);
                (d[r+1]+=F[r-l+2])%=mod;
                num+=(d[r+1]!=0);
            }
            if(r+2<=n)
            {
                num-=(d[r+2]!=0);
                (d[r+2]+=F[r-l+1])%=mod;
                num+=(d[r+2]!=0);
            }
        }
        if(num)printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

结论

对于将一个数组的一个区间同时加上另一个数组且加上的这个数组中的元素都能通过同样的规律从前面的元素中算得的这样一类题目都能通过差分来思考。


__EOF__

本文作者Jerry-Black
本文链接https://www.cnblogs.com/Jerry-Black/p/15885679.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
posted @   Jerry_Black  阅读(103)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示