2017-10-07离线赛
来源:互联网 发布:沈阳 苹果直营店 知乎 编辑:程序博客网 时间:2024/05/18 16:14
大体状况
240/300
T1 simple
题目大意
求
分析
P60
这个不定方程虽然是exgcd的形式,
然而完全可以写DP,然后直接计算。
实际上就是个暴力。
P100
因为不会写,
又看到
就考虑在
然后调了一会凑出了答案,对拍无误。
代码
瞎写。
#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)#define LL long longvoid Rd(int &res){ char c;res=0; while((c=getchar())<48); do res=(res<<3)+(res<<1)+(c^48); while((c=getchar())>47);}void Rd(LL &res){ char c;res=0; while((c=getchar())<48); do res=(res<<3)+(res<<1)+(c^48); while((c=getchar())>47);}int T,n[14],m[14];LL q[14],mx;struct P60{ static const int M=100004; int DP[M]; void Solve(){ REP(t,0,T){ REP(i,0,M)if(i%n[t])DP[i]=0; else DP[i]=1; REP(i,0,M-m[t]-1)if(DP[i]) DP[i+m[t]]=1; REP(i,0,M)DP[i]=!DP[i]; REP(i,1,M)DP[i]+=DP[i-1]; printf("%d\n",DP[q[t]]); } }}P60;struct P100{ static const int M=100004; LL DP[M]; int Q[M]; void Solve(){ REP(t,0,T){ memset(DP,63,sizeof(DP)); int A=DP[0]=0; LL val=0; while(1){ (A+=m[t])%=n[t]; val+=m[t]; if(val>q[t])break; if(val<DP[A])DP[A]=val; else break; } LL Ans=q[t]; REP(i,0,M)if(DP[i]!=0x3f3f3f3f3f3f3f3f){ Ans-=(q[t]-DP[i])/n[t]+1; } Ans++; printf("%lld\n",Ans); } }}P100;int main(){ freopen("simple.in","r",stdin); freopen("simple.out","w",stdout); Rd(T); REP(t,0,T)Rd(n[t]),Rd(m[t]),Rd(q[t]),chkmax(mx,q[t]); if(mx<=100000)P60.Solve(); else P100.Solve(); return 0;}
T2 walk
题目大意
求树上每一种长度的路径所得到的边权最大Gcd。
P30
暴力枚举一个起点。
暴力搜索同时计算Gcd。
暴力更新答案。
P100
然后发现答案应该是单调递减的。
边权的范围较小,所以可以枚举答案。
然后用边权为答案的倍数的这些边建森林,
求每棵树的直径,取最大值用于更新即可。
代码
比赛时没有枚举答案倍数,弄了一个枚举边权因子。
为此写了线性筛素数与其副产品线性拆质因子。
以及DFS枚举因子和时间戳类链表。
速度十分慢,还好是卡过去了。
#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define LL long long#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)#define M 400004#define pb push_back#define SZ(a) ((int)(a).size())void Rd(int &res){ char c;res=0; while((c=getchar())<48); do res=(res<<3)+(res<<1)+(c^48); while((c=getchar())>47);}#define LREP(i,A) for(int i=Head[A];i;i=Next[i])int n;struct P30{ int Next[M<<1],V[M<<1],W[M<<1],Head[M],tot; void Add_Edge(int u,int v,int w){ Next[++tot]=Head[u],V[Head[u]=tot]=v,W[tot]=w; } int Gcd(int a,int b){ return b?Gcd(b,a%b):a; } int Ans[1004]; void DFS(int A,int f,int d,int num){ int B; if(d)chkmax(Ans[d],num); LREP(i,A)if((B=V[i])!=f) DFS(B,A,d+1,Gcd(W[i],num)); } void Solve(){ REP(i,1,n){ int u,v,w; Rd(u),Rd(v),Rd(w); Add_Edge(u,v,w); Add_Edge(v,u,w); } memset(Ans,0,sizeof(Ans)); REP(i,1,n+1)DFS(i,0,0,0); REP(i,1,n+1)printf("%d\n",Ans[i]); }}P30;struct P100{ static const int Mx=1000004; int Pri[Mx>>1],pt; int B[Mx]; int U[M],V[M],Tmp[20]; bool Vis[20]; int Ans[M],space; vector<int>Use[Mx]; void Updata(int x,int cnt,int num,int id){ if(x==cnt)return; if(x && !Vis[x-1] && Tmp[x]==Tmp[x-1]){ Updata(x+1,cnt,num,id); return; } Updata(x+1,cnt,num,id); Vis[x]=1; num*=Tmp[x]; Use[num].pb(id);space++; Updata(x+1,cnt,num,id); Vis[x]=0; } void Init(){ REP(i,2,Mx){ if(!B[i])Pri[pt++]=B[i]=i; REP(j,0,pt){ LL pos=1ll*i*Pri[j]; if(pos>=Mx)break; B[pos]=Pri[j]; if(!(i%Pri[j]))break; } } } int Next[M<<1],Go[M<<1],Tim[M],Head[M],tot,Time; void Add_Edge(int u,int v){ if(Tim[u]!=Time)Tim[u]=Time,Head[u]=0; Next[++tot]=Head[u],Go[Head[u]=tot]=v; } void TreeClear(){ Time++; tot=0; } bool Mark[M]; int Dis[M]; int DFS(int A,int f,int &To){ Mark[A]=1; Dis[A]=Dis[f]+1; if(Dis[A]>Dis[To])To=A; int B; LREP(i,A)if((B=Go[i])!=f) DFS(B,A,To); } void Check(int PAns){ if(!SZ(Use[PAns]))return; TreeClear(); int sz=0; REP(i,0,SZ(Use[PAns])){ int j=Use[PAns][i]; Mark[U[j]]=Mark[V[j]]=0; Add_Edge(U[j],V[j]); Add_Edge(V[j],U[j]); } int Res=1; REP(i,0,SZ(Use[PAns])){ int j=Use[PAns][i]; if(!Mark[U[j]]){ int LT,RT;LT=RT=0; Dis[0]=-1; DFS(U[j],0,LT); DFS(LT,0,RT); chkmax(Res,Dis[RT]); } }// cerr<<Res<<","<<PAns<<endl; chkmax(Ans[Res],PAns); } void Solve(){ Init(); memset(Ans,0,sizeof(Ans)); REP(i,1,n){ int cnt=0,w; Rd(U[i]),Rd(V[i]),Rd(w); chkmax(Ans[1],w); while(B[w])Tmp[cnt++]=B[w],w/=B[w]; Updata(0,cnt,1,i); Add_Edge(U[i],V[i]); Add_Edge(V[i],U[i]); } int LT,RT;LT=RT=0; Dis[0]=-1; DFS(1,0,LT); DFS(LT,0,RT); chkmax(Ans[Dis[RT]],1); REP(i,2,Ans[1]+1) Check(i); DREP(i,n,1) chkmax(Ans[i],Ans[i+1]); REP(i,1,n+1) printf("%d\n",Ans[i]); }}P100;int main(){ freopen("walk.in","r",stdin); freopen("walk.out","w",stdout); Rd(n); if(n<=1000)P30.Solve(); else P100.Solve();// cerr<<(sizeof(P30)+sizeof(P100)+P100.space*4.0)/1024/1024<<endl; return 0;}
T3 travel
题目大意
在数轴上瞎跳,求从s开始刚好向左跳L次并刚好经过每个点一次的最小距离以及这个跳跃方案。
P10
P???
比赛时间还剩30分钟
思考一下,发现很可能不走回头路,
于是就分为两种情况直接贪心了。
然而这个贪心是错的。
然后水了40分。
P100
然后确实是贪心,但是不是那么蠢。
还是会走回头路的,此时可以用掉一个L。
代价就是这一条线段要走3遍。
枚举结束节点e,使s始终在e左侧。
然后可以得到一种方案,
在s左侧都走两遍,在e右侧也走两遍,用掉n-e+s-1个L,
此时在中间取L个最小线段走三次即可。
然后反向搜索,
由于取的线段一直在变少,可以直接用一个队列维护。
找到答案后随便求出一个可行的方案即可。
代码
感觉几乎是抄题解。
#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)#define LL long long#define INF 0x3f3f3f3f3f3f3f3fvoid Rd(int &res){ char c;res=0; while((c=getchar())<48); do res=(res<<3)+(res<<1)+(c^48); while((c=getchar())>47);}#define M 200004int n,l,s,X[M],Y[M];int Ans1[M],Ans2[M];LL ans1,ans2;struct Node{ int v,x; bool operator <(const Node &P)const{ return v<P.v; }}D[M];int Pos[M];bool Mark[M];void Solve(int l,int s,int *Ans,int *X,LL &ans){ int len=0,tot=0; if(l<=s-1){ ans=0LL+X[n]-X[1]+X[s]-X[1]; DREP(i,l,0)Ans[len++]=i; REP(i,l+1,n+1)if(i!=s)Ans[len++]=i; return; } l-=s-1; if(l==n-s-1){ ans=0LL+X[n]-X[1]+X[s]-X[1]+X[n]-X[s+1]; REP(i,1,s)Ans[len++]=i; DREP(i,n,s)Ans[len++]=i; return; } LL Sum=0,Mn,Val; REP(i,s+2,n) D[++tot]=(Node){X[i]-X[i-1],i}; sort(D+1,D+tot+1); REP(i,1,tot+1)Pos[D[i].x]=i; REP(i,1,l+1)Sum+=D[i].v; Mn=Sum<<1; int mn=l,p=l,e=n; DREP(i,n-1,n-l-1){ if(Pos[i]<=p)Sum-=D[Pos[i]].v; else Sum-=D[p--].v; while(p && D[p].x>=i)p--; if((Val=((Sum<<1)+X[n]-X[i]))<Mn) Mn=Val,e=i,mn=p; } DREP(i,s-1,0)Ans[len++]=i; REP(i,s+2,e)Mark[i]=Pos[i]<=mn; for(int i=s+1;i<e;i++){ int tmp=i+1; if(!Mark[tmp])Ans[len++]=i; else { while(Mark[tmp])tmp++; DREP(j,tmp-1,i-1)Ans[len++]=j; i=tmp-1; } } DREP(i,n,e-1)Ans[len++]=i; ans=0LL+X[n]-X[1]+X[s]-X[1]+Mn;}int main(){ Rd(n),Rd(l),Rd(s); REP(i,1,n+1)Rd(X[i]),Y[n-i+1]=-X[i]; if((l==0 && s!=1) || (l==n-1 && s!=n) || l>n-1){ puts("-1"); return 0; } Solve(l,s,Ans1,X,ans1); Solve(n-l-1,n-s+1,Ans2,Y,ans2); if(ans1<=ans2){ printf("%lld\n",ans1); REP(i,0,n-1)printf("%d%c",Ans1[i]," \n"[i==n-2]); } else{ printf("%lld\n",ans2); REP(i,0,n-1)printf("%d%c",n-Ans2[i]+1," \n"[i==n-2]); } return 0;}
总结
其实好像是Rank1来着,
?运气比较好,大概吧。
注意一下实现了,T2写得太麻烦了,
数据卡一下可能还会因为常数大的关系死掉。
- 2017-10-07离线赛
- 2017-10-10离线赛
- 2017-10-09离线赛
- 2017-10-06离线赛
- 2017-10-12离线赛
- 2017-10-15离线赛
- 2017-10-16离线赛
- 2017-10-17离线赛
- 2017-10-18离线赛
- 2017-10-10离线赛总结
- 2017-10-3离线赛小结
- 2017-10-4离线赛总结
- 2017-10-6离线赛总结
- 2017-10-7离线赛题解
- 2017-10-7离线赛总结
- 2017-10-8离线赛总结
- 2017-10-9离线赛总结
- 2017-10-12离线赛总结
- 使用CMake来进行Android NDK开发
- Matlab数据分析、图形处理与机器学习算法实现培训班
- SQL-利用默认自动记录时间
- Linux基础操作(六)
- 【JavaScript】!!的作用
- 2017-10-07离线赛
- 插入排序(直接插入排序--折半插入排序--谢尔排序)
- Git使用详细教程
- 聊聊Vue.js的template编译
- 判断一颗树是否是镜像
- Reactive Programming
- 减法变加法------补码----同余理论
- H5传播渠道
- 浅析局域网与广域网中数据传输