组队赛4th 2017中国大学生程序设计竞赛-杭州站

本文介绍了三道编程竞赛题目,涉及字符串处理、数组操作和博弈论。第一题通过贪心策略找到使所有奇数长度子串变为回文串的最小操作次数;第二题利用差分数组和快速幂计算区间GCD;第三题通过博弈论分析确定在特定条件下谁能赢得石子游戏。
摘要由CSDN通过智能技术生成

比赛链接
A - Super-palindrome (贪心)
在这里插入图片描述
题意:
给定一个字符串,每次可以改变任意一个字母,求使所有长度为奇数的子串变为回文串的最小操作次数
题目分析:
签到题,随便举个例子可以发现,满足要求的字符串必须满足奇数位和偶数位的字符全部相等
代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=1e9+7;
const int N=110;
int odd[N],even[N];
char s[N];
signed main(){
    fast;
    int T;
    cin>>T;
    while(T--){
        memset(odd,0,sizeof(odd));
        memset(even,0,sizeof(even));
        cin>>s+1;
        int n=strlen(s+1);
        for(int i=1;i<=n;i++){
            if(i&1) odd[s[i]-'a']++;
            else even[s[i]-'a']++;
        }
        int maxv=-1;
        int sum=0;
        for(int i=0;i<26;i++)
            maxv=max(maxv,odd[i]);
        sum+=maxv;
        maxv=-1;
        for(int i=0;i<26;i++)
            maxv=max(maxv,even[i]);
        sum+=maxv;
        cout<<n-sum<<endl;
    }
    return 0;
}

J - Master of GCD(差分+快速幂)
在这里插入图片描述
题意:
长度为n的数组初始化为1,然后进行m次操作,每次使区间 [l,r ]上的数乘上2或3,最后求区间的gcd
题目分析:
第一眼以为是线段树,然后抄了板子调了半天没调对(发现自己线段树写的好差),然后队友给的思路统计2和3出现的次数,答案就是2的最小次数次方乘上3的最小次数次方,数据较大,统计次数可以用差分数组来维护。
代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=998244353;
const int N=1e5+10;
int a2[N],b2[N];
int a3[N],b3[N];
int n,m;
int qmi(int a,int b,int p)
{
    int res=1%p;
    while(b){
        if(b&1) res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}
signed main()
{
    fast;
    int T;
    cin>>T;
    while(T--){
        memset(a2,0,sizeof(a2));
        memset(b2,0,sizeof(b2));
        memset(a3,0,sizeof(a3));
        memset(b3,0,sizeof(b3));
        cin>>n>>m;
        while(m--){
            int l,r,c;
            cin>>l>>r>>c;
            if(c==2){
                b2[l]++;
                b2[r+1]--;
            }
            else if(c==3){
                b3[l]++;
                b3[r+1]--;
            }
        }
        int min2=INF,min3=INF;
        for(int i=1;i<=n;i++){
            a2[i]=b2[i]+a2[i-1];
            a3[i]=b3[i]+a3[i-1];
            min2=min(min2,a2[i]);
            min3=min(min3,a3[i]);
        }
        int ans=1;
        ans=qmi(2,min2,mod);
        ans=ans*qmi(3,min3,mod)%mod;
        cout<<ans%mod<<endl;
    }
    return 0;
}

C - Hakase and Nano(思维+博弈)
在这里插入图片描述
题意:
给定n堆石子的个数和先后手顺序,第一个人可以选择一堆石子拿走至少一个石子,第二个人可以操作两次,谁拿走最后一堆谁赢,如果第二个人赢输出Yes,否则输出No
题目分析:博弈题必胜必败态的寻找是一个重要的解题点,通过分析我们可以得知第二个人如果先手,他必败的状态必定是n是3的倍数且所有堆的石子个数均为1,如果第一个人先手,我们可以思考什么情况下可以通过一次操作转化为第二个人的必败态,因为我们可以操作一次,一种情况是n-1为3的倍数且堆数为1的个数为n-1或n,另一种情况是n为3的倍数,且1的个数为n-1
代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=998244353;
const int N=1e6+10;
int n,op;
int a[N];
signed main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&op);
        int cnt=0;
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            if(a[i]==1) cnt++;
        }
        if(op==1){
            if(n%3==0&&cnt==n)
                puts("No");
            else
                puts("Yes");
        }
        else{
            if((n%3==1&&cnt>=n-1)||(n%3==0&&cnt==n-1))
                puts("No");
            else
                puts("Yes");
        }
    }
    return 0;
}

B D 待补

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值