【NOIP2010】提高组
T1机器翻译
直接上队列的模拟题,日常没题解。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 int m,n; 5 int read(){ 6 int ans=0,f=1;char c=getchar(); 7 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 8 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 9 return ans*f; 10 } 11 int q[1005],h=1,t=0; 12 bool ok[1005]; 13 int main(){ 14 m=read();n=read(); 15 int sum=0; 16 for(int i=1,a;i<=n;i++){ 17 a=read(); 18 if(ok[a])continue; 19 sum++;if(!m)continue; 20 q[++t]=a;ok[a]=1; 21 if(t-h+1>m)ok[q[h]]=0,h++; 22 } 23 printf("%d",sum); 24 return 0; 25 }
T2乌龟棋
f[i][j][k][p]表示四种卡片分别用了i、j、k.、p张,然后n4转移就没了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 int read(){ 5 int ans=0,f=1;char c=getchar(); 6 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 7 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 8 return ans*f; 9 } 10 int max(int x,int y){return x>y?x:y;} 11 int f[45][45][45][45]; 12 int a[355],count[5]; 13 int main(){ 14 int n=read(),m=read(); 15 for(int i=1;i<=n;i++)a[i]=read(); 16 for(int i=1,b;i<=m;i++)b=read(),count[b]++; 17 for(int i=0;i<=count[1];i++){ 18 for(int j=0;j<=count[2];j++){ 19 for(int k=0;k<=count[3];k++){ 20 for(int p=0;p<=count[4];p++){ 21 int now=i+j*2+k*3+p*4+1; 22 int p1=0,p2=0,p3=0,p4=0; 23 if(i)p1=f[i-1][j][k][p]; 24 if(j)p2=f[i][j-1][k][p]; 25 if(k)p3=f[i][j][k-1][p]; 26 if(p)p4=f[i][j][k][p-1]; 27 f[i][j][k][p]=max(max(p1,p2),max(p3,p4))+a[now]; 28 } 29 } 30 } 31 } 32 printf("%d",f[count[1]][count[2]][count[3]][count[4]]); 33 return 0; 34 }
T3关押罪犯
后来成为并查集的经典题,i和i+n表示对立的两个集合。
将冲突关系按怒气值从大到小排个序。
每次尝试把两名罪犯放到不同的两个集合里,发现已经在同一个集合里就可以直接输出答案了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 const int N=2e4+10,M=1e5+10; 5 int fa[N*2]; 6 int n,m; 7 struct node{ 8 int fr,to,w; 9 bool operator <(const node&p)const {return p.w<w;} 10 }e[M]; 11 int getf(int x){return x==fa[x]?x:fa[x]=getf(fa[x]);} 12 int read(){ 13 int ans=0,f=1;char c=getchar(); 14 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 15 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 16 return ans*f; 17 } 18 int main(){ 19 n=read();m=read(); 20 for(int i=1;i<=n;i++)fa[i]=i,fa[i+n]=i+n; 21 for(int i=1,a,b,c;i<=m;i++){ 22 a=read();b=read();c=read(); 23 e[i]=(node){a,b,c}; 24 } 25 std::sort(e+1,e+1+m); 26 for(int i=1;i<=m;i++){ 27 int p1=e[i].fr,p2=e[i].to,w=e[i].w; 28 int f1=getf(p1),f2=getf(p2); 29 if(f1==f2)return printf("%d",w),0; 30 int fa1=getf(p1+n),fa2=getf(p2+n); 31 fa[f1]=fa2;fa[f2]=fa1; 32 } 33 printf("0"); 34 return 0; 35 }
T4引水入城
灌水法,先从顶端dfs染色,扫一遍最下一层,如果有点没被染色就说明不能满足要求。
然后从下往上反灌水,因为顶层的点所覆盖的底层的点必然是连续的一段(反证法),因此就变成了去最少的线段覆盖给定的区间问题。
按左端点排个序然后不断往后贪心拓展就好了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mem(a,p) memset(a,p,sizeof(a)) 5 const int N=505; 6 using std::sort; 7 using std::max; 8 struct node{int li,ri;}e[N]; 9 int n,m,tot=0,mp[N][N],cc[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; 10 int read(){ 11 int ans=0,f=1;char c=getchar(); 12 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 13 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 14 return ans*f; 15 } 16 int f[N][N],li[N][N],ri[N][N]; 17 int xx[4]={1,-1,0,0},yy[4]={0,0,1,-1}; 18 int qx[250005],qy[250005]; 19 bool cmp(node a,node b){return a.li<b.li;} 20 void dfs(int x,int y){ 21 for(int i=0;i<4;i++){ 22 int px=x+cc[i][0],py=y+cc[i][1]; 23 if(px<1||px>n||py>m||py<1||f[px][py]||mp[px][py]>=mp[x][y])continue; 24 f[px][py]=f[x][y]; 25 dfs(px,py); 26 } 27 } 28 void dfs1(int x,int y){ 29 for(int i=0;i<4;i++){ 30 int px=x+cc[i][0],py=y+cc[i][1]; 31 if(px<1||px>n||py<1||py>m||mp[px][py]<=mp[x][y])continue; 32 bool flag=0; 33 if(li[px][py]>li[x][y])li[px][py]=li[x][y],flag=1; 34 if(ri[px][py]<ri[x][y])ri[px][py]=ri[x][y],flag=1; 35 if(flag)dfs1(px,py); 36 } 37 } 38 int main(){ 39 n=read();m=read(); 40 for(int i=1;i<=n;i++) 41 for(int j=1;j<=m;j++) 42 mp[i][j]=read(); 43 for(int i=1;i<=m;i++)f[1][i]=1; 44 for(int i=1;i<=m;i++)dfs(1,i); 45 int sum=0;bool flag=0; 46 for(int i=1;i<=m;i++)if(!f[n][i])flag=1,sum++; 47 if(flag)return printf("0\n%d",sum),0; 48 mem(li,127); 49 for(int i=1;i<=m;i++)li[n][i]=ri[n][i]=i; 50 for(int i=1;i<=m;i++)dfs1(n,i); 51 for(int i=1;i<=m;i++) 52 if(li[1][i]!=li[0][0]) 53 e[++tot]=(node){li[1][i],ri[1][i]}; 54 sort(e+1,e+1+tot,cmp); 55 int now=0,to=0; 56 for(int i=1;i<=tot;i++){ 57 if(now+1>=e[i].li)to=max(to,e[i].ri); 58 else now=to,to=max(to,e[i].ri),sum++; 59 } 60 if(now!=to)sum++; 61 printf("1\n%d",sum); 62 return 0; 63 }