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]);
}
为什么随便选的一场都这么水啊...