USACO 2.2
USACO 2.2.1
题解:
先模拟将阿拉伯数字转化为罗马数组,再统计就好了。
代码:
{ ID:m1599491 PROG:preface LANG:PASCAL } const Rome:array[1..13] of string[2]=('M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'); const Arab:array[1..13] of longint=(1000,900,500,400,100,90,50,40,10,9,5,4,1); var n,i,j:longint; var s:string; var sum:array[1..7] of longint; var chara:array[1..7] of char=('I','V','X','L','C','D','M'); function ch(x:longint):string; var i:longint; var R:string; begin R:=''; for i:=1 to 13 do while x>=Arab[i] do begin R:=R+Rome[i]; x:=x-Arab[i]; end; exit(R); end; function num(s:string):byte; begin if s='I' then exit(1);if s='V' then exit(2); if s='X' then exit(3);if s='L' then exit(4); if s='C' then exit(5);if s='D' then exit(6); if s='M' then exit(7); end; begin assign(input,'preface.in');reset(input); assign(output,'preface.out');rewrite(output); readln(n); for i:=1 to n do begin s:=ch(i); for j:=1 to length(s) do inc(sum[num(s[j])]); end; for i:=1 to 7 do if sum[i]<>0 then writeln(chara[i],' ',sum[i]); close(input);close(output); end.
USACO 2.2.2
题解:
题目要求的是将一个集合(1...N)划分成两个和相等的集合的方案数,那么就相当于在N个数里面找出和为∑(1...N)*½的组数,就是背包咯。(还可以特判下∑(1...N)如果为奇数就直接输出0
代码:
{ ID:m1599491 PROG:subset LANG:PASCAL } var n,m,i,j:longint; var f:array[0..39,0..390] of longint; begin assign(input,'subset.in');reset(input); assign(output,'subset.out');rewrite(output); readln(n); m:=(n+1)*n>>1; if m and 1=1 then begin writeln(0);close(input);close(output);halt; end; m:=m>>1; f[0,0]:=1; for i:=1 to n do for j:=1 to m do if j>=i then f[i,j]:=f[i-1,j]+f[i-1,j-i] else f[i,j]:=f[i-1,j]; writeln(f[n,m]); close(input);close(output); end.
USACO 2.2.3
题解:
xjb模拟就好咯,之前自己的代码A了之后忘了保存,就copy了别人的(逃
代码:
/* ID:m1599491 PROG:runround LANG:C++ */ #include<stdio.h> #include<string.h> #include<math.h> #include<stdlib.h> int q[10000],front,rear; int vis[20];int bis[20]; int ok(long x) { memset(vis,0,sizeof(vis)); memset(bis,0,sizeof(bis)); int k=(int)log10(x)+1; int kk=1; while(x>0) { if(!(x%10)) return 0; q[k-kk]=x%10; kk++;x/=10; } for(int i=0;i<k;i++) vis[q[i]]++; for(int i=1;i<10;i++) if(vis[i]>1) return 0; front=0;rear=k; for(int i=0;i<k;i++) { int j=q[front]; bis[j]++; if(bis[j]>1) return 0; front=(front+j)%k; } if(front!=0) return 0; return 1; } int main() { freopen("runround.in","r",stdin); freopen("runround.out","w",stdout); memset(q,0,sizeof(q)); long n; scanf("%d",&n); for(long i=n+1;;i++) if(ok(i)) { printf("%d\n",i); break; } return 0; }
USACO 2.2.4
题解:
这道题有点强。
仔细想想会发现:1+2=3;1+3=2;2+3=1;1+2+3=啥都没做;同一个按键按两次=啥都没做。这样一来,你会发现不管你怎么xjb按,最终都可以化简为以下8种情况:1,2,3,4,1+4,2+4,3+4,不按(C=0)。
所以只要C>2就统统可以化为0≤C≤2的情况。
当C=0:不按;当C=1:1,2,3,4;当C=2:1+4,2+4,3+3。
然后还有一个特点就是,1号灯永远等于7号灯,2号灯永远等于8号灯,……,i号灯永远等于i+6号灯,这样子就只需要求出前6位(000000,001110,010101,011011,100100,101010,110001),后面的循环输出就好。
代码:
/* LANG:C++ PROG:lamps ID:m1599491 */ #include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<string> using namespace std; int n,c,i,j,k,A[10],B[10],on[1000]; string s[10]; bool fflag=0; bool OK(int x) { if (c>2) return 1; if (c==0 && x==7) return 1; if (c==1 && (x==0 || x==2 || x==3 || x==5)) return 1; if (c==2 && (x==1 || x==4 || x==6)) return 1; return 0; } void writeln(int n,int x) { int point=0; fflag=1; while (n) { printf("%d",s[x][point]-48); if (point==5) point=0; else point++; n--; } printf("\n"); } main() { freopen("lamps.in","r",stdin); freopen("lamps.out","w",stdout); scanf("%d",&n);scanf("%d",&c); for (i=1; i<=n; i++) on[i]=2; scanf("%d",&k);while (k>-1) {on[k]=1;scanf("%d",&k);} scanf("%d",&k);while (k>-1) {on[k]=0;scanf("%d",&k);} s[0]="000000";s[1]="001110";s[2]="010101";s[3]="011011";s[4]="100100";s[5]="101010";s[6]="110001";s[7]="111111"; for (i=1; i<=6; i++) B[i]=2; for (i=1; i<=n; i++) { if (i%6==0){if (on[i]==1) B[6]=1;if (on[i]==0) B[6]=0;} else {if (on[i]==1) B[i%6]=1;if (on[i]==0) B[i%6]=0;} } for (i=0; i<=7; i++) { bool flag=0; for (j=0; j<6; j++) {if (B[j+1]!=2 && B[j+1]!=s[i][j]-48) flag=1;} if (!flag && OK(i)) writeln(n,i); } if (!fflag) printf("IMPOSSIBLE\n"); return 0; }