【Codeforces】#Round467 Div2

本文解析了CodeforcesRound467Div2的五道题目,包括求大于0的数值个数、寻找不可整除的最大数、节能策略、睡眠游戏胜负判断及锁谜题解法。通过代码示例详细介绍了每道题目的解决思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门:CodeforcesRound467Div2


A. Olympiad

求大于0的数值个数。sort一遍。听说可以用set

#include<bits/stdc++.h>
using namespace std;
int ans,n,a[102]; 
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;++i){
        if(a[i]==0) continue;
        if(a[i]!=a[i-1]) ans++; 
    } 
    printf("%d",ans);

} 

B. Vile Grasshoppers

求区间k+1-n之间最大的不能被1-k之间数整除的数,不存在则输出-1
筛一波素数以后强势枚举。
时间复杂度很迷,然而并没有T…
看了官方解答:

Why does this approach work? Note that the the nearest prime less or equal to y is valid. At the same time the prime gap of numbers less than billion doesn’t exceed 300 and we’re gonna factorize no more than 300 numbers in total. Therefore the complexity is .

若不存在,则n-k必然小于300,存在,则最多300次可以枚举到

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,y;
int p[N+100],tot;
bool pri[N+100];

void pre(){
    memset(pri,true,sizeof(pri));
    for(int i=2;i<=N && i*i<=1000000000;++i){
        if(pri[i]){
            p[++tot]=i;
           for(int j=i*i;1ll*j*j<=1000000000;j+=i) pri[j]=false;
        }
    }
} 
int main(){
   pre();int jud=0,i,j,t;
   scanf("%d%d",&y,&n);
   for(i=n-((n&1)^1);i>y;i-=2){
    t=1;
     for(j=1;j<=tot&&p[j]<=y;++j){
        if(i%p[j]==0) {t=0;break;}
    }
    if(t) break;
   }
   if(i>y)printf("%d\n",i);
   else printf("-1\n");
} 

C. Save Energy!

按开启关闭一轮算,先轮完整数轮,剩下的单独讨论一下即可。

#include<bits/stdc++.h>
#define db double
using namespace std;
typedef long long ll;
ll k,d,t,res,wh,rd,trd,wk,rs,now;
db ans;

int main(){
    scanf("%I64d%I64d%I64d",&k,&d,&t);
    wh=t<<1; 
    if(k<d){
        res=d-k;wk=2*k;rd=wk+res;
        now=wh/rd*d;
        ans+=now;now=wh%rd;
        if(now<=wk) ans+=(db)now/2;
        else{
            ans+=k;now-=wk;ans+=now;
        }
        printf("%.10lf\n",ans); 
    }else if(k%d==0){
        printf("%.10lf\n",(db)t); 
    }else{
        res=k%d;wk=2*k;res=d-res;rd=wk+res;
        ans+=(wh/rd)*(k+res);now=wh%rd;
        if(now<=wk) ans+=(db)now/2;
        else{
            ans+=k;now-=wk;ans+=now;
        }
        printf("%.10lf\n",ans);
    }
} 

D. Sleepy Game

如果能找到一条长度为奇数的路径可以走到一个出度为0的点,就赢了。
一开始理解错题意了。
注意题目中的这句话:

Your task is to help Petya find out if he can win the game or at least draw a tie.

能不能赢,或至少平局。而且题中是一个人同时操作双方,并没有要求双方都按最优策略走。
考虑到以上条件,此题就顿时变水了QWQ。
我们爆搜一遍找路径,没有就找环

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+20,M=1e5+10;
int head[M],to[N],nxt[N];
int vis[M][2],vs[M],fr[M][2];
int n,m,tot,op,S;
vector<int>q;
inline int rd()
{
    char ch=getchar();int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
 }

inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}

inline void dfs(int x,int f,int d)
{
    if(vis[x][d]==1) return;
    vis[x][d]=1;fr[x][d]=f;
    for(int i=head[x];i;i=nxt[i]) 
        dfs(to[i],x,d^1);
}

inline bool loop(int x)
{
    vs[x]=1;int sta=0;
    for(int i=head[x];i;i=nxt[i]){
        if(vs[to[i]]==1)sta=1;else if(vs[to[i]]==0){
            sta=loop(to[i]);
        } 
        if(sta) return true;
    }
    vs[x]=2;
    return false;
}

int main(){
    int i,j,ix,iy;
    n=rd();m=rd();
    for(i=1;i<=n;++i){
        ix=rd();
        for(j=1;j<=ix;++j){
            iy=rd();lk(i,iy);
        } 
    } 
    S=rd();
    dfs(S,0,0);int jud=0; 
    for(i=1;i<=n;++i){
        if(!head[i] && vis[i][1]){
            int qw=i,d=1;q.push_back(qw);
            while(fr[qw][d]){
                qw=fr[qw][d];d^=1;
                q.push_back(qw);
            }
            printf("Win\n");
            for(j=q.size()-1;j>=0;j--) printf("%d ",q[j]);
            jud=1;
            break;
        }
    }
    if(!jud){
        if(loop(S)) printf("Draw");
        else printf("Lose\n");
    }
}

E. Lock Puzzle

此题真的妙妙啊,想不到很难,一看到题解又觉得自己zz了。
注意长度<=2000,操作<=6005
分明就是在提示我们,每三次操作,可以将某个指定的数换到字符串最后一个的位置,又不影响之前拍好的几个位置。
代码也有一些技巧:

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

int n,ans[6010],cnt;
char s[2002],t[2002];

inline void  rev(int x)
{
    if(!x) return;
    reverse(s,s+n);
    reverse(s+x,s+n);
    ans[++cnt]=x;
}

int main(){
    int op=0,r;
    scanf("%d%s%s",&n,s,t);
    for(int i=0;i<n;++i){
        r=0;
        while(s[r]!=t[i] && r<n){r++;}
        if(r>=n-i) {printf("-1\n");return 0;}
        rev(n-r-1);
        rev(1);
        rev(n-1); 
    }
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;++i) printf("%d ",ans[i]);
} 

为什么随便选的一场都这么水啊...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值