noip2016 提高组
T1 玩具谜题 题目传送门
这道题直接模拟就好了哇 233
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=1e5+7; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,k,v,ans=1; char s[M][25]; int h[M]; int main() { n=read(); m=read(); for(int i=1;i<=n;i++) h[i]=read(),scanf("%s",s[i]);//0朝内1朝外 for(int i=1;i<=m;i++){ k=read(); v=read(); if(!k) v=-v; if(h[ans]) v=-v; ans=ans+v; if(ans<1) ans=ans+n; if(ans>n) ans=ans-n; } printf("%s",s[ans]); return 0; }
T2 天天爱跑步 题目传送门
这道题我 真的 看不懂..... 跳 以后填坑
T3 换教室 最短路+dp 题目传送门
这道题是道期望dp f【i】【j】【k】代表到第i个时段换了j个教师k代表当前点换不换(1换0不换) 然后就是一波递推了
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=2007; const double inf=1e15; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,v,s,c[M],d[M]; double k[M],f[M][M][2],dis[M][M],w; void prepare(){ for(int i=1;i<=v;i++) for(int j=1;j<=v;j++) dis[i][j]=(i==j)?0:inf; for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) f[i][j][0]=f[i][j][1]=inf; f[1][0][0]=0; f[1][1][1]=0; // for(int i=1;i<=n;i++,printf("\n")) for(int j=1;j<=v;j++) printf("[%.2lf %.2lf] ",f[i][j][0],f[i][j][1]); } void floyd(){ for(int k=1;k<=v;k++) for(int i=1;i<=v;i++) for(int j=1;j<=v;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); // for(int i=1;i<=v;i++,printf("\n")) for(int j=1;j<=v;j++) printf("%.2lf ",dis[i][j]); } int main() { int x,y; n=read(); m=read(); v=read(); s=read(); for(int i=1;i<=n;i++) c[i]=read(); for(int i=1;i<=n;i++) d[i]=read(); for(int i=1;i<=n;i++) scanf("%lf",&k[i]); prepare(); for(int i=1;i<=s;i++){ x=read(); y=read(); scanf("%lf",&w); dis[x][y]=dis[y][x]=min(dis[x][y],w); } floyd(); for(int i=2;i<=n;i++){ for(int j=0;j<=m;j++){ if(!j) {f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+dis[c[i-1]][c[i]]); continue;} f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+dis[c[i-1]][c[i]]); f[i][j][0]=min(f[i][j][0],f[i-1][j][1]+dis[d[i-1]][c[i]]*k[i-1]+dis[c[i-1]][c[i]]*(1-k[i-1])); f[i][j][1]=min(f[i][j][1],f[i-1][j-1][0]+dis[c[i-1]][d[i]]*k[i]+dis[c[i-1]][c[i]]*(1-k[i])); double d1=k[i]*k[i-1]*dis[d[i-1]][d[i]],d2=k[i]*(1-k[i-1])*dis[c[i-1]][d[i]]; double d3=(1-k[i])*k[i-1]*dis[d[i-1]][c[i]],d4=(1-k[i])*(1-k[i-1])*dis[c[i-1]][c[i]]; f[i][j][1]=min(f[i][j][1],f[i-1][j-1][1]+d1+d2+d3+d4); } } double ans=inf; for(int i=0;i<=m;i++) ans=min(ans,f[n][i][0]),ans=min(ans,f[n][i][1]); printf("%.2lf\n",ans); return 0; }
T4 组合数问题 题目传送门
这道题 搜索打一波发现是个类似杨辉三角的东西 然后就维护一波前缀和方便计算就好了哇 其实可以跑两波实现o(1) 查询 不过 我懒啦 233
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=2007; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } LL f[M][M],sum[M][M]; LL n,m,T,k,ans; void prepare(){ for(LL i=0;i<M;i++) f[i][0]=1; for(LL i=1;i<M;i++) for(LL j=1;j<=i;j++){ f[i][j]=(f[i-1][j]+f[i-1][j-1])%k; if(!f[i][j]) sum[i][j]=1; sum[i][j]+=sum[i][j-1]; } } int main() { for(T=read(),k=read(),prepare();T;T--){ n=read(); m=read(); ans=0; for(LL i=1;i<=n;i++) ans=ans+sum[i][min(i,m)]; printf("%lld\n",ans); } return 0; }
T5 蚯蚓 题目传送门
这道题其实就是维护三个队列q1是原队列 按从小到达sort一波 以后都不会有更新了 q2,q3分别储存砍完的前后半段 可以证明两个队列都是单调递减的 然后整体的加转化成个体的减的好了
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=1e7+7; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } LL n,m,q,u,v,k; LL h1=1,h2=1,h3=1,t2,t3; LL q1[M],q2[M],q3[M]; bool cmp(LL a,LL b){return a>b;} LL push_max(LL x){ LL sum=-0x3f3f3f3f3f3f3f3f; if(h1<=n) sum=max(sum,q1[h1]); if(h2<=t2) sum=max(sum,q2[h2]); if(h3<=t3) sum=max(sum,q3[h3]); if(h1<=n&&q1[h1]==sum) h1++; else if(h2<=t2&&q2[h2]==sum) h2++; else h3++; //printf("[%lld]\n",sum+q*(x-1)); return sum+q*(x-1); } int main() { n=read(); m=read(); q=read(); u=read(); v=read(); k=read(); for(int i=1;i<=n;i++) q1[i]=read(); sort(q1+1,q1+1+n,cmp); //for(int i=1;i<=n;i++) printf("[%d] ",q1[i]); for(LL i=1;i<=m;i++){ LL sum=push_max(i); if(i%k==0) printf("%lld ",sum); LL now=sum*u/v; //printf("[%lld %lld]\n",now,sum-now); q2[++t2]=now-i*q; q3[++t3]=sum-now-i*q; }printf("\n"); for(LL i=1;i<=n+m;i++){ LL sum=push_max(m+1); if(i%k==0) printf("%lld ",sum); } return 0; }
当然优先队列也可以打部分分 但是因为m太大了 nlog(n+m) 会T 只能拿六十分 贴一波T的代码啦
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define LL long long using namespace std; const int M=1e7+7; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } LL x; struct node{ LL w; bool operator < (const node &x)const {return w<x.w;} }; priority_queue<node>qu; int n,m,q,u,v,k; int main() { n=read(); m=read(); q=read(); u=read(); v=read(); k=read(); for(int i=1;i<=n;i++) x=read(),qu.push((node){x}); // while(!qu.empty()){node x=qu.top(); printf("%lld\n",x.w); qu.pop();} for(int i=1;i<=m;i++){ node x=qu.top(); qu.pop(); LL sum=x.w+(i-1)*q,now=sum*u/v,cur=sum-now; qu.push((node){now-i*q}); qu.push((node){cur-i*q}); if(i%k==0) printf("%lld ",sum); }printf("\n"); for(int i=1;i<=n+m;i++){ node x=qu.top(); qu.pop(); LL sum=x.w+m*q; if(i%k==0) printf("%lld ",sum); } return 0; }
T6 愤怒的小鸟 题目传送门
这是一道状压dp g【i】【j】表示经过i,j两个点的二次函数一共能经过的点数
然后根据这个可以推出一波答案 不过要记得算一只鸟只打死一只猪的情况就好了
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int M=25; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int T,n,m; int g[M][M],f[1<<M],id[M]; double x[M],y[M],a,b; bool pd(double x,double y){return fabs(x-y)<1e-6;} void push_ans(){ n=read(); m=read(); for(int i=1;i<=n;i++) scanf("%lf %lf",&x[i],&y[i]); memset(g,0,sizeof(g)); for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ if(pd(x[i],x[j])) continue; a=(y[i]/x[i]-y[j]/x[j])/(x[i]-x[j]); if(a>=0) continue; b=y[i]/x[i]-a*x[i]; int sum=0; for(int k=1;k<=n;k++) if(pd(a*x[k]+b,y[k]/x[k])) sum+=id[k]; g[i][j]=sum; } } memset(f,0x3f,sizeof(f)); f[0]=0; for(int k=0;k<(1<<n);k++) for(int i=1;i<=n;i++){ if(id[i]&k) continue; for(int j=i+1;j<=n;j++) f[k|g[i][j]]=min(f[k|g[i][j]],f[k]+1); f[id[i]|k]=min(f[id[i]|k],f[k]+1); } printf("%d\n",f[(1<<n)-1]); } int main() { for(int i=1;i<M;i++) id[i]=1<<(i-1); for(T=read();T;T--) push_ans(); return 0; }