Codeforces Round #467(Div2)题解

本文分享了作者凌晨参与 CodeForces 比赛的经历及解题思路,涉及五道题目的算法实现,包括计数、质数判断、模拟、图论以及字符串处理等。

凌晨起来打CF,0:05,也是我第一次codeforces

第一题:

我刚开始怀疑自己读错题了,怎么会辣么水。

判除了0的数字种类

#include <cstdio>
int n,ans=0;
bool hsh[610];
int main(){
    scanf("%d",&n);int i;
    for(i=1;i<=n;++i){
        int x;scanf("%d",&x);if(!hsh[x] && x)++ans,hsh[x]=1;
    }
    printf("%d",ans);
}

第二题:让你找一个x使x<=y且x不能被[2,p]内的数整除,使x尽量大

其实是暴力枚举。

#include <cstdio>
int p,y;
bool ck(int x){
    int i;
    for(i=2;i*i<=x&&i<=p;++i)if(x%i==0)return 0;
    return 1;
}
int main(){
    scanf("%d%d",&p,&y);
    int i;
    for(i=y;i>p;--i)if(ck(i)){
        printf("%d",i);
        return 0;
    }
    printf("-1");
}

第三题,模拟题,太水了,不细说:

#include <cstdio>
#include <iostream>
using namespace std;
long long k,d,t;
double ans=0;
int main(){
    scanf("%I64d%I64d%I64d",&k,&d,&t);if(k%d==0){
        printf("%I64d",t);
        return 0;
    }
    long long tmp=(k/d+1)*d;tmp-=k; 
    double x=k,y=(double)tmp/2;
    long long tm=(long long)((double)t/(x+y));ans=tm*(k+tmp);double rt=(double)t-(double)tm*(x+y);
    if(rt<=k){
        ans+=rt;printf("%lf",ans);
    }else{
        ans+=k;rt-=k;ans+=rt*(double)2;printf("%lf",ans);
    }
}

第四题:

给你一个有向图,问你能否奇数步走到一个初度为0的点,输出路径

初看吓得我以为是SG函数,然而并不是, tarjan+bfs就行了

bfs和dp一起来,这里的dp可以用spfa的方式,用一个可以让元素多次进出的队列,然后搞dp

tarjan用来判能不能平局,如果s以后的路上没有scc,就输出lose

#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
#define maxn 100010
#define maxm 200010
struct edge{int nxt,to;}e[maxm];
int ans[maxn],out[maxn],scc_size[maxn],head[maxn],pos,n,m,scc[maxn],dfs_cnt,scc_cnt,i,st,dnf[maxn],low[maxn],pre[maxn][2];
bool dp[maxn][2],inq[maxn];
void add(int u,int v){e[++pos]=(edge){head[u],v},head[u]=pos;}
stack<int>s;
queue<int>q;
void tar(int u){
    dnf[u]=low[u]=++dfs_cnt;s.push(u);int i;
    for(i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(!dnf[v]){
            tar(v);low[u]=min(low[u],low[v]);
        }else if(!scc[v])low[u]=min(low[u],dnf[v]);
    }
    if(low[u]==dnf[u]){
        for(scc_cnt++;;){
            int x=s.top();s.pop();++scc_size[scc_cnt];
            scc[x]=scc_cnt;if(x==u)break;
        }
    }
}
void dfs(int u,int sta){
    if(u){
        dfs(pre[u][sta],sta==1 ? 0:1);
        ans[++ans[0]]=u;
    }
}
int main(){
    scanf("%d%d",&n,&m);int i;
    for(i=1;i<=n;++i){
        int k,x;scanf("%d",&k);
        while(k--){
            scanf("%d",&x);add(i,x);++out[i];
        }
    }
    scanf("%d",&st);
    for(i=1;i<=n;++i)if(!dnf[i])tar(i);
    bool flg=0;
    dp[st][0]=1;q.push(st);inq[st]=1;
    while(!q.empty()){
        int u=q.front();q.pop();inq[u]=0;
        if(scc_size[scc[u]]>1)flg=1;
        for(i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(dp[u][1] && dp[v][0]==0){
                dp[v][0]=1;pre[v][0]=u;if(!inq[v])q.push(v),inq[v]=1;
            }
            if(dp[u][0] && dp[v][1]==0){
                dp[v][1]=1;pre[v][1]=u;if(!inq[v])q.push(v),inq[v]=1;
            }
        }
    }
    for(i=1;i<=n;++i)if(dp[i][1] && out[i]==0){
        dfs(i,1);printf("Win\n");
        for(int j=1;j<=ans[0];++j)printf("%d ",ans[j]);return 0;
    }
    if(flg)printf("Draw");else printf("Lose");
}

T5:构造题

题意是给定一个字符串S1,S2(这不是两个吗。。。)长度2e3以下

定义操作:

将s1的后缀x个进行一次反转,再放到字符串首

如果操作多余6100,则答案无效

分析:

对于一个字符串:ABxC(A:与s2后缀相符的字符串,x:S2后缀A之前的那个字符,也就是我们要将x放到A前面,B,C:都是无关紧要的乱序字符串)

ABxC->CxBA(每个都反转)->ABCx->xABC 操作次数3n

#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 2010
char s1[maxn],s2[maxn];
int n,ans[6110],h1[27],h2[27];
int idx(char c){return c-'a';}
bool jg(){
    for(int i=0;i<n;++i)if(s1[i]!=s2[i])return 0;
    return 1;
}
bool ck(int l1,int r1,int l2,int r2){
    for(;l1<=r1;++l1,++l2)if(s1[l1]!=s2[l2])return 0;
    return 1;
}
int main(){//freopen("o1.txt","w",stdout);
    scanf("%d",&n);
    scanf("%s",s1);scanf("%s",s2);int len=0;
    int i;
    for(i=0;i<n;++i)h1[idx(s1[i])]++,++h2[idx(s2[i])];
    for(i=0;i<27;++i)if(h1[i]!=h2[i]){
        printf("-1");return 0;
    }
    while(!jg()){
        int apos=-1,bpos=-1,cpos=-1,xpos=-1;
        for(i=n;i>=len && !ck(0,i-1,n-i,n-1);--i);len=i;
        apos=len-1;
        for(i=apos+1;s1[i]!=s2[n-len-1];++i);
        bpos=i-1;xpos=i;cpos=n;
        ans[++ans[0]]=n;ans[++ans[0]]=bpos+1;ans[++ans[0]]=1;
        char tmp[maxn];
        tmp[0]=s2[n-len-1];int ps=0;
        for(i=0;i<=apos;++i)tmp[++ps]=s1[i];
        for(i=apos+1;i<=bpos;++i)tmp[++ps]=s1[i];
        //for(i=xpos+1;i<n;++i)tmp[++ps]=s1[i];
        for(i=n-1;i>=xpos+1;--i)tmp[++ps]=s1[i];
        for(i=0;i<n;++i)s1[i]=tmp[i];
    }
    printf("%d\n",ans[0]);
    for(int i=1;i<=ans[0];++i)printf("%d ",ans[i]);
}

 

转载于:https://www.cnblogs.com/david--lj/p/8476596.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值