Codeforces Round #467 (div.2)

我才不会打这种比赛呢
(其实本来打算打的)
谁叫它推迟到了 00:05
我爱睡觉

题解

A. Olympiad

翻译

给你若干人的成绩
让你划定一个分数线
使得所有不低于这个分数线的人都可以获奖
但是 0 分的人一定不能得奖
问你有多少种获奖情况

题解

sort+unique 然后判断一下最小值是不是 0 就行了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int n,a[500];
int main()
{
    n=read();
    for(int i=1;i<=n;++i)a[i]=read();
    sort(&a[1],&a[n+1]);
    int tot=unique(&a[1],&a[n+1])-a-1;
    if(a[1]==0)tot--;
    printf("%d\n",tot);
    return 0;
}

B. Vile Grasshoppers

翻译

给定p,y
2..y 内找到一个最大值 x
使得x不能被 2..p 整除
无解输出 1

题解

看到范围这么大。
真是吓死人
首先考虑一下怎么检查一个值 x 是否可行
当然不需要枚举2..p
最多只需要枚举到 x

如果有解,要么 p 很小,要么y很大
很容易就可以枚举出来
如果无解, p 一定要很接近y
这样不需要枚举多少个数
复杂度 O(???)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
ll ans=0;
int main()
{
    int p,y;
    cin>>p>>y;
    for(int ans=y;ans>p;--ans)
    {
        bool fl=true;
        for(int i=2;i<=p&&i*i<=ans;++i)
            if(ans%i==0){fl=false;break;}
        if(fl){cout<<ans<<endl;return 0;}
    }
    puts("-1");
    return 0;
}

C. Save Energy!

翻译

有一个人要煮鸡吃
但是炉子每过 k 分钟就会自动关上
这个人每过d分钟会进厨房,如果炉子关上了他就会打开

炉子在打开的时候鸡只需要 t 分钟就可以煮熟
在关上的时候则需要2t分钟
问这个人多久以后可以吃到鸡

题解

这题很简单啊
首先如果 K%d=0 就不用考虑了
否则我们一定能够找到一个最小的 x
使得xd>K
这样子的话,我们发现开关状态以 xd 循环
接下来只要分类讨论就行了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
ll K,d,t;
int main()
{
    cin>>K>>d>>t;t*=2;
    if(K%d==0){cout<<t/2<<endl;return 0;}
    ll st=K/d+1;
    ll T=st*d;
    ll ts=2*K+(T-K);
    double ans=t/ts*T;t%=ts;
    if(t<=2*K)ans+=t/2.0;
    else
    {
        ans+=K;
        t-=2*K;
        ans+=t;
    }
    printf("%.10lf\n",ans);
    return 0;
}

D. Sleepy Game

翻译

有两个人在玩一个游戏
有一个棋子和有向图
一开始棋子在某个位置
然后两个人轮流走
谁先走不了谁就输了
如果超过了 106 步则平局
但是现在第二个人睡觉去了
两个人都由第一个人操控
问第一个人能不能赢,如果能输出路径
否则输出平局或者必败

题解

首先考虑能不能赢
因为能不能赢
只和到达一个出度为 0 的点的路径的奇偶性有关
所以用一个BFS检查能否以某个奇偶性到达某个点
如果有出度为 0 的点满足条件,则输出路径

考虑平局,即能够到达某个环
第一步检查了能否到达
这样找到环以后判断一下就好
如果也不能平局,则必败,输出即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 120000
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Line{int v,next;}e[MAX*2];
int h[MAX],cnt=1,n,m,H[MAX],B;
int dis[MAX][2],zy[MAX][2];
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
void outp(int now,int k,int w)
{
    if(!(k==now&&!w))outp(now,zy[k][w],w^1);
    printf("%d ",k);
}
bool bfs(int now)
{
    queue<pair<int,int> >Q;
    Q.push(make_pair(now,0));
    dis[now][0]=1;
    while(!Q.empty())
    {
        int u=Q.front().first,w=Q.front().second;Q.pop();
        for(int i=h[u];i;i=e[i].next)
        {
            int v=e[i].v;
            if(dis[v][w^1])continue;
            zy[v][w^1]=u;
            dis[v][w^1]=1;
            Q.push(make_pair(v,w^1));
        }
    }
    for(int i=1;i<=n;++i)
        if(!H[i]&&dis[i][1])
        {
            puts("Win");outp(now,i,1);puts("");
            return true;
        }
    return false;
}
int dfn[MAX],low[MAX],tim;
int S[MAX],top,G[MAX];
bool vis[MAX];
bool Ans;
void Tarjan(int u)
{
    S[++top]=u;vis[u]=true;
    dfn[u]=low[u]=++tim;
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].v;
        if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]);
        else if(vis[v])low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
        int v,size=0;
        do{v=S[top--];vis[v]=false;G[++size]=v;}while(u!=v);
        if(size!=1)
            for(int i=1;i<=size;++i)
                if(dis[G[i]][0]||dis[G[i]][1])Ans=true;
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)
    {
        H[i]=read();
        for(int j=1;j<=H[i];++j)Add(i,read());
    }
    B=read();
    if(bfs(B))return 0;
    for(int i=1;i<=n;++i)if(!dfn[i])Tarjan(i);
    if(Ans)puts("Draw");
    else puts("Lose");
    return 0;
}

E. Lock Puzzle

翻译

给定一个串s和目标串 s

你每次都可以执行一个 shift 操作

执行 shift(x)

假设原来的串是 s=AB

那么,现在的串变为了 BRA

其中, B 的长度等于x

说白点,就是把后 x 个字符翻转后,放在字符串的最前面

(举个例子,原来是ababc ,执行 shift(3) 后,变为了 cbaab

执行操作的次数不能超过 6100

无解输出 1

题解

我们假设前面已经匹配好了 i1

现在匹配第 j

那么,现在当前串中找到一个和目标位置相同的字符,位置是pos

然后考虑 shift 操作

当然,只需要执行 shift(npos),shift(1),shift(n) 三次操作就行了

我们假设当前串是 AcB 其中 c=s[pos]

shift(npos) 之后 BRAc

shift(1) 之后 cBRA

shift(n) 之后 ARBc

这样的话,我们发现后面的位置就不会再变化了

而每次我们都把当前的目标字符给挪到了最后一个位置

这样执行 3n 次操作之后就可以得到目标串了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 5000
int n,a[26],b[26];
char s[MAX],ss[MAX];
char s1[MAX],s2[MAX];
vector<int> ans;
void shift(char *s,int x)
{
    int t1=0,t2=0;
    for(int i=n-x+1;i<=n;++i)s2[++t2]=s[i];
    reverse(&s2[1],&s2[t2+1]);
    for(int i=1;i<=n-x;++i)s1[++t1]=s[i];
    for(int i=1;i<=x;++i)s[i]=s2[i];
    for(int i=1;i<=t1;++i)s[i+t2]=s1[i];
    ans.push_back(x);
}
int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    scanf("%s",ss+1);
    for(int i=1;i<=n;++i)a[s[i]-97]++,b[ss[i]-97]++;
    for(int i=0;i<26;++i)if(a[i]!=b[i]){puts("-1");return 0;}
    for(int i=1;i<=n;++i)
    {
        int pos;
        for(int j=1;j<=n;++j)
            if(s[j]==ss[i]){pos=j;break;}
        shift(s,n-pos);shift(s,1);shift(s,n);
    }
    printf("%d\n",(int)(ans.size()));
    for(int i=0;i<ans.size();++i)
        printf("%d ",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值