游记#2019杭电单人ACM

吐槽

竟然一定要单人参加,还好不是英文啊qwq
4个小时9道题,我jio的4道题差不多了
签到题交了5发,有点自闭;树形dp调不对,有点自闭
封榜的时候,发现一个bug,竟然还可以看别人的提交记录233
结束之后,真的只有4道题啊qwq
这里放一下,别的题不放了

T1-电子锁

这是杭州电子科技大学第九十届程序设计竞赛。以往每个选手在解锁电脑时都需要将信封里的密码条拿出来,将上面的密码输入到电脑中。这回不太一样,学校刚安装了一批电子锁,选手只需要将密码条放在电脑的摄像头前,电脑就会自动识别出上面的密码。
每个选手的密码都是一个仅由大小写英文字母和数字’0’到’9’组成的字符串。
你是这场比赛的技术人员,就在比赛即将开始前的几分钟,你发现打印的密码条上数字’0’和大写字母’O’,以及小写字母’l’和大写字母’I’过于相似。你对学校新引进的电子锁不太放心,于是决定修改识别部分的逻辑,使得’0’和’O’、’l’和’I’也算匹配。
比赛马上就要开始了,抓紧时间吧!

解法

签到题,然而我交了好多遍
原因是:数字0->大写字母O,小写字母l->大写字母I,打错了=-=

ac代码

#include
#include
#include
#include
#include
#include
#include
using namespace std;
int t,n,flg;
char st[50],c;
int main()
{
    scanf("%d",&t); 
    while(t--)
    {
        scanf("%d",&n),flg=0,cin >> st;
        for(int i=0;i> c;
            if(st[i]=='0')st[i]='O';
            if(st[i]=='l')st[i]='I';
            if(c=='0')c='O';
            if(c=='l')c='I';
            if(c!=st[i])flg=1;
        }
        if(flg)puts("NO");
        else puts("OK");
    }
    return 0;
}

T2-交通灯

相信交通灯对于你来说并不陌生,交通灯分为红色和绿色两个阶段,这两个阶段互相更替,保障着道路的安全。
在杭州一共有n个路口,编号依次为1到n。这些路口之间连接着m条双向道路,每条道路连接着两个不同的路口,且任意两个路口之间最多连接着一条道路。每条道路中央都设置着一个交通灯。
为了保障道路的安全,对于任意两条道路,如果它们连接了同一个路口,那么它们不能同色。
你的朋友正乘着飞机从杭州的上空飞过,并拍了一张杭州的照片。在照片里,每条道路的交通灯的颜色都清晰可辨。
你并不知道你的朋友是在什么时候按下的快门,于是你想统计出有多少种可能的方案。每个方案可以用一个颜色序列col1,col2,…,colm(coli∈{′Red′,′Green′})来描述,表示每个交通灯的颜色。

解法

这道题是真的坑,一开始上手了这道题,打了个树形dp,炸了,调了半个小时,没调出来,就先去做其他题目了
把能做的几道题做完后,又回到了这道题,想了一下,如果单纯的把边的颜色放到点上是会炸掉的
于是又开始调,先写了个初始颜色放在度为1的边上,后来又发现有一些点可能是孤立的,答案会莫名乘上个2
然后还是调,在提交了n次之后,终于过了,具体实现就看代码吧

ac代码

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int mod=1e9+7;
struct edge{int to,next;}a[200010];
int t,n,m,x,y,head[100010],cnt,vis[100010],flg,du[100010],used[200010],dep[100010];
long long ans,color[100010][2];
void add()
{
    a[++cnt]={y,head[x]},head[x]=cnt;
    a[++cnt]={x,head[y]},head[y]=cnt;
}
void dfs(int u)
{
    vis[u]=1;
    for(int i=head[u];i!=-1;i=a[i].next)
    {
        if(!vis[a[i].to])dfs(a[i].to);
        color[u][1]=(1ll*color[u][1]*color[a[i].to][0])%mod;
        color[u][0]=(1ll*color[u][0]*color[a[i].to][1])%mod;
    }
}
void dfsx(int u,int fa)
{
    if(ans==0)return ;
    if(vis[u])
    {
        if(abs(dep[fa]+1-dep[u])%2)ans=0;
        return ;
    }
    vis[u]=1,dep[u]=dep[fa]+1;
    for(int i=head[u];i!=-1;i=a[i].next)
        if(!used[i])used[i]=1,used[i|1]=1,dfsx(a[i].to,u);
}
//环如果长度为奇数,答案就是0
//每一个环也会贡献一个2倍
void check()
{
    memset(used,0,sizeof(used)),memset(dep,0,sizeof(dep));
    for(int i=1;i<=n;i++)if(!vis[i]&&du[i]!=0)flg++,dfsx(i,0);
}
//检查有没有环
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(head,-1,sizeof(head)),memset(vis,0,sizeof(vis)),memset(du,0,sizeof(du));
        scanf("%d%d",&n,&m),cnt=-1,ans=1,flg=0;
        for(int i=1;i<=n;i++)color[i][0]=color[i][1]=1;
        for(int i=1;i<=m;i++)scanf("%d%d",&x,&y),add(),du[x]++,du[y]++;
        for(int i=1;i<=n;i++)if(!vis[i]&&du[i]==1)
            flg++,color[i][1]=0,dfs(i),ans=(1ll*ans*((color[i][0]+color[i][1])%mod))%mod;
        else if(du[i]>2)ans=0;
        //只能在度为1的点开始搜,如果度大于2就一定没有答案
        if(ans!=0)check();
        for(int i=1;i<=flg;i++)ans=(1ll*ans*2)%mod;
        //每一个连通块会贡献一个2倍
        printf("%lld\n",ans);
    }
    return 0;
}

T3-三色抽卡游戏

你的对手太坏了!在每年的年度三色抽卡游戏锦标赛上,你的对手总是能打败你,他的秘诀是什么?
在每局三色抽卡游戏中,有n个卡组,每个卡组里所有卡片的颜色都相同,且颜色只会是红(R)、绿(G)、蓝(B)中的一种。第i个卡组有vi张卡片。
对决双方每次只能选择一个还未抽完卡的卡组,从中拿走若干张卡片,可以全拿走,但不能一张都不拿。你只能选择颜色为红或者绿的卡组,而对手只能选择颜色为蓝或者绿的卡组。
你是先手,你和对手轮流行动,谁不能操作了就输了。
因为你的对手每次总是能打败你,你决定写一个程序来帮助你做出决策。
给定游戏刚开始时的卡组情况,你的程序需要判断假设双方都按照最优策略操作,那么你是否会赢?

解法

一开始没想出来,后来仔细一想,将绿色看成一个没有限制条件的取石子,那先手获胜的判断方法就是异或和是否为0
如果先手能在取绿色中获胜,那只要红色数量大于等于蓝色数量,先手必胜
如果先手不能在取绿色中获胜,那就需要红色数量大于蓝色数量才能使先手必胜

ac代码

#include
#include
#include
#include
#include
#include
#include
using namespace std;
int t,n,x,a,b,c;
char ch;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n),a=b=c=0;
        for(int i=1;i<=n;i++)
        {
            cin >> ch >> x;
            if(ch=='R')a+=x;
            else if(ch=='B')b+=x;
            else c^=x;
        }
        if(c)a++;
        if(a>b)puts("YES");
        else puts("NO");
    }
    return 0;
}

T4-质数串

一个正整数x是质数,当且仅当x≥2且x不是任何一个[2,x?1]的数的倍数。
一个数字串是”质数串”,当且仅当它的每个非空连续子串表示的数字都是质数。
例子1:”373″是质数串,它的子串有”3″、”37″、”373″、”7″、”73″、”3″,这些串表示的数字都是质数。
例子2:”55″不是质数串,因为”55″这个子串表示的数字不是质数。
相信聪明的你一定已经发现了一个事实,那就是质数串的限制很紧,所以质数串的数量其实非常稀少。
给定一个长度为n的数字串S,请统计它有多少个非空连续子串是质数串。注意两个子串如果位置不同也算不同,比如”373373″中,”373″要算入答案两次。

解法

看起来很难,其实推一下就知道了
一位的,只能是2 3 5 7
两位的,只能是23 53 37 73
三位的,只能是373
好了木有了,是不是很简单233

ac代码

#include
#include
#include
#include
#include
#include
#include
using namespace std;
int t,n,a[100010],b[100010],ans,cek[5],ccekk[5];
void check(int i)
{
    if(a[i]==1||a[i]==4||a[i]==6||a[i]==8||a[i]==9)b[i]=1;
    if(a[i]==2||a[i]==5)b[i]=2;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(b,0,sizeof(b)),scanf("%d",&n),ans=0;
        for(int i=1;i<=n;i++)scanf("%1d",&a[i]),check(i);
        for(int i=1;i<=n;i++)
        {
            if(b[i]==1)continue;
            ans++;
            if(i==n)continue;
            if(b[i+1])continue;
            if(b[i]){if(a[i+1]==3)ans++;continue;}
            if(a[i]!=a[i+1]){ans++;if(a[i]==7||i==n-1)continue;if(a[i]==a[i+2])ans++;}
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(游记#2019杭电单人ACM)