[NOIP2015总结]
来源:互联网 发布:tcpdump 指定端口抓包 编辑:程序博客网 时间:2024/05/16 08:48
Day1:
T1:
直接模拟就行。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=100; int n,ans[N][N]; struct S{int x,y;}a[N*N]; int main(){ int i,j,x,y; scanf("%d",&n); ans[1][n/2+1]=1; a[1].x=1;a[1].y=n/2+1; for(i=2;i<=n*n;++i){ x=a[i-1].x;y=a[i-1].y; if(x==1&&y!=n){ ans[n][y+1]=i; a[i].x=n;a[i].y=y+1; } else if(x!=1&&y==n){ ans[x-1][1]=i; a[i].x=x-1;a[i].y=1; } else if(x==1&&y==n){ ans[x+1][y]=i; a[i].x=x+1;a[i].y=y; } else{ if(x-1>0&&y+1<=n&&!ans[x-1][y+1]){ ans[x-1][y+1]=i; a[i].x=x-1;a[i].y=y+1; } else{ ans[x+1][y]=i; a[i].x=x+1;a[i].y=y; } } } for(i=1;i<=n;++i){ for(j=1;j<=n;++j) printf("%d ",ans[i][j]); printf("\n"); } return 0; }
T2:
题目是让求出一个最小环,因为是有向图而且每个点只有一条出边,所以直接dfs就行。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=200010; bool check; struct S{int st,en;}aa[N*10]; int n,a[N],tot,ans,point[N],next[N*10],f[N],use[N]; inline int in(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } inline void add(int x,int y){ tot+=1;next[tot]=point[x];point[x]=tot; aa[tot].st=x;aa[tot].en=y; } inline void find(int x,int y,int z){ int i; if(check) return ; f[x]=y;use[x]=z; for(i=point[x];i;i=next[i]){ if(use[aa[i].en]==0) find(aa[i].en,y+1,z); else if(use[aa[i].en]==z){ ans=min(ans,y-f[aa[i].en]+1); check=true; return ; } } } int main(){ int i,num=0; n=in(); for(i=1;i<=n;++i) a[i]=in(),add(i,a[i]); ans=0x7fffffff; for(i=1;i<=n;++i) if(!use[i]){ num+=1; check=false; find(i,1,num); } printf("%d\n",ans); return 0; }
T3:
刚看到题的时候感觉像是一个最短路??状压??
但是感觉应该写不完,所以直接写的暴力。
后来听了TA爷说的,可以给操作编上号以后按照顺序直接dfs就行了。
#include<iostream>#include<cstdio>#include<cstring>using namespace std;int T,n,a[30],b[30],ans;//1:三顺子 2:双顺子 3:单顺子 4:三带二,一 6:四带二 inline bool check(){ for(int i=1;i<=15;++i) if(a[i]) return false; return true;}inline void dfs(int x,int y){ int i,j,k,kind,sum=0; if(y>=ans) return ; if(check()){ ans=min(ans,y); return ; } for(i=1;i<=13;++i) sum+=a[i]?1:0; sum+=a[14]+a[15]?1:0; ans=min(ans,y+sum); for(kind=x;kind<=5;++kind){ if(kind==1){ for(i=1;i<=11;++i) if(a[i]>=3) for(j=i+1;j<=12&&a[j]>=3;++j){ for(k=i;k<=j;++k) a[k]-=3; dfs(x,y+1); for(k=i;k<=j;++k) a[k]+=3; } } if(kind==2){ for(i=1;i<=10;++i) if(a[i]>=2&&a[i+1]>=2) for(j=i+2;j<=12&&a[j]>=2;++j){ for(k=i;k<=j;++k) a[k]-=2; dfs(x,y+1); for(k=i;k<=j;++k) a[k]+=2; } } if(kind==3){ for(i=1;i<=8;++i){ sum=0; for(j=i;j<=i+3;++j) if(a[j]) sum+=1; if(sum!=4) continue; for(j=i+4;j<=12&&a[j];++j){ for(k=i;k<=j;++k) a[k]-=1; dfs(x,y+1); for(k=i;k<=j;++k) a[k]+=1; } } } if(kind==4){ for(i=1;i<=15;++i) if(a[i]>=3){ a[i]-=3; for(j=1;j<=15;++j) if(a[j]>=2) a[j]-=2,dfs(x,y+1),a[j]+=2; a[i]+=3; } for(i=1;i<=15;++i) if(a[i]>=3){ a[i]-=3; for(j=1;j<=15;++j) if(a[j]) a[j]-=1,dfs(x,y+1),a[j]+=1; a[i]+=3; } } if(kind==5){ for(i=1;i<=15;++i) if(a[i]>=4){ a[i]-=4; for(j=1;j<=15;++j) if(a[j]>=2){ a[j]-=2; for(k=j;k<=15;++k) if(a[k]>=2) a[k]-=2,dfs(x,y+1),a[k]+=2; a[j]+=2; } a[i]+=4; } for(i=1;i<=15;++i) if(a[i]>=4){ a[i]-=4; for(j=1;j<=15;++j) if(a[j]){ a[j]-=1; for(k=j;k<=15;++k) if(a[k]) a[k]-=1,dfs(x,y+1),a[k]+=1; a[j]+=1; } a[i]+=4; } } }}int main(){ scanf("%d%d",&T,&n); while(T--){ int i,j,x,y; memset(a,0,sizeof(a)); for(i=1;i<=n;++i){ scanf("%d%d",&x,&y); if(!x) a[y+13]+=1; if(x>=3) a[x-2]+=1; if(x>0&&x<3) a[x+11]+=1; } ans=0; for(i=1;i<=13;++i) ans+=a[i]?1:0; ans+=a[14]+a[15]?1:0; dfs(1,0); printf("%d\n",ans); }}
Day2
T1:
二分答案+贪心验证。贪心的时候直接扫一遍就行了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define mid (l+r)/2 const int N=50010; int L,n,m,a[N]; inline bool check(int x){ int now=0,sum=0,i; for(i=2;i<=n+2;++i){ if(a[i]-now>=x){ now=a[i]; } else{ sum+=1; } } return sum<=m; } int main(){ int i,j; scanf("%d%d%d",&L,&n,&m); a[n+2]=L; for(i=1;i<=n;++i) scanf("%d",&a[i+1]); int l=0,r=L,ans=0; while(l<=r){ if(check(mid)) ans=max(ans,mid),l=mid+1; else r=mid-1; } printf("%d\n",ans); return 0; }
T2:
首先70分的dp很好写,就是f[i][j][k]表示到第一个的i,第二个的j,分成了k段的答案。那么首先处理出到i,j时连续的相同的长度,就比较好转移了。
那么满分的就是将转移的时候的枚举改成前缀和就好了。注意这个题还卡内存,所以需要将k的那一维滚了。
#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define D 1000000007const int M=210;const int N=1010;char s1[N],s2[M];int n,m,k,f[2][N][M],sum[N][M];inline char in(){ char ch=getchar(); while(ch<'a'|ch>'z') ch=getchar(); return ch;}int main(){ int i,j,p,now=0; scanf("%d%d%d",&n,&m,&k); sum[0][0]=1; for(i=1;i<=n;++i) s1[i]=in(),sum[i][0]=1; for(i=1;i<=m;++i) s2[i]=in(); for(i=1;i<=n;++i) for(j=1;j<=m;++j) sum[i][j]=(s1[i]==s2[j])?sum[i-1][j-1]:0; while(k--){ now^=1; memset(f[now],0,sizeof(f[now])); for(i=1;i<=n;++i) for(j=1;j<=min(m,i);++j) f[now][i][j]=(f[now][i-1][j]+(s1[i]==s2[j]?sum[i][j]:0))%D; for(i=0;i<=n;++i) sum[i][0]=0; for(i=0;i<=m;++i) sum[0][i]=0; for(i=1;i<=n;++i) for(j=1;j<=m;++j) sum[i][j]=(s1[i]==s2[j])?((sum[i-1][j-1]+f[now][i-1][j-1])%D):0; } printf("%d\n",f[now][n][m]);}
T3:
又是二分答案,主要的问题是在二分之后我们怎样去判断呢?
对于一个二分的答案mid,我们首先找出所有总长度大于mid的路线,然后我们求出这些路线的交,再找出交中最大的边减去,看看符不符合。
对于上面说的我们可以先处理处经过每条边的路线的数目,怎样统计呢?
我们对于一条边x,y,和他们的lca,在节点x和y处+1,在lca处-2,这样我们遍历一遍所有的节点,统计每一个父亲处的权值和后,就可以算出这个父亲的上一条边有多少路径经过了。
但是这种做法会背卡5分的常数,UOJ上好像有线性的做法,有时间的时候写一写吧。
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define mid (l+r)/2#define inf 0x7fffffffconst int N=300010;struct Q{int x,y,lca,dis;}q[N];struct S{int st,en,va;}aa[N*2];int n,m,tot,point[N],next[N*2],fa[N][20],deep[N],dis[N],maxlen,maxn,v[N];inline int in(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x;}inline void add(int x,int y,int z){ tot+=1;next[tot]=point[x];point[x]=tot; aa[tot].st=x;aa[tot].en=y;aa[tot].va=z; tot+=1;next[tot]=point[y];point[y]=tot; aa[tot].st=y;aa[tot].en=x;aa[tot].va=z;}inline void prepare(int x,int last){ int i,j; for(i=1;i<=19&&deep[x]>=(1<<i);++i) fa[x][i]=fa[fa[x][i-1]][i-1]; for(i=point[x];i;i=next[i]) if(aa[i].en!=last){ deep[aa[i].en]=deep[x]+1; fa[aa[i].en][0]=x; dis[aa[i].en]=dis[x]+aa[i].va; prepare(aa[i].en,x); }}inline int LCA(int x,int y){ if(deep[x]<deep[y]) swap(x,y); int t=deep[x]-deep[y],i; for(i=0;i<=19;++i) if(t&(1<<i)) x=fa[x][i]; for(i=19;~i;--i) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return x==y?x:fa[x][0];}inline int work(int x,int last){ int i,sum=v[x]; for(i=point[x];i;i=next[i]) if(aa[i].en!=last) sum+=work(aa[i].en,x); if(sum==tot) maxn=max(maxn,dis[x]-dis[fa[x][0]]); return sum;}int main(){ int i,j,x,y,z; n=in();m=in(); for(i=1;i<n;++i){ x=in();y=in();z=in(); add(x,y,z); } prepare(1,0); for(i=1;i<=m;++i){ q[i].x=in();q[i].y=in(); q[i].lca=LCA(q[i].x,q[i].y); q[i].dis=dis[q[i].x]+dis[q[i].y]-2*dis[q[i].lca]; maxlen=max(maxlen,q[i].dis); } int l=0,r=maxlen; while(l<r){ tot=maxn=0; memset(v,0,sizeof(v)); for(i=1;i<=m;++i) if(q[i].dis>mid) tot+=1,v[q[i].x]+=1,v[q[i].y]+=1,v[q[i].lca]-=2; work(1,0); if(maxlen-maxn<=mid) r=mid; else l=mid+1; } printf("%d\n",l);}
1 0
- NOIP2015 总结
- NOIP2015总结
- NOIP2015总结
- Noip2015总结
- NOIP2015总结
- noip2015总结
- NOIP2015总结
- NOIP2015 总结
- 【NOIP2015】总结
- NOIP2015总结
- [NOIP2015总结]
- Noip2015总结
- noip2015总结
- NOIP2015总结
- NOIP2015总结
- 【NOIP2015 10.22模拟】总结
- 【NOIP2015 模拟10.27】总结
- 【NOIP2015 10.29模拟】总结
- JFrame基础
- 轻松搞定面试中的红黑树问题
- javafx form
- IIC总线协议
- Android Fragment 你应该知道的一切
- [NOIP2015总结]
- iOS
- META:网页上的元信息(meta-information)标签
- 车辆检测“Integrating Context and Occlusion for Car Detection by Hierarchical And-Or Model”
- debian上安装zabbix
- 学习笔记_android之复制黏贴实现方法
- 记录使用hibernate时遇到的问题
- 网页嵌套视频 swf
- ubuntu apache django 布署