第一题:
给你N个字符串 ,你每次 可以 选择 其中 一个 字符串 的一段 前缀 进行 翻转 ,但 是你必须 保证 这个 前缀 的长度 是偶数 。你可以 进行 无限次 这样 的操作 ,并且如果两个字符串 变得 相同 的时候 ,你就可以把这两个字符串都删除掉,问最后最少剩下多少个字符串 ?n<=50, t( t 组数据)<=11
解: 一直觉得这道题很神奇。写了好久的草稿,结果还是没看出来。其实根据偶数这个性质,只要再深入一点就可以发现了。无论如何翻转,原本相邻的 i 和 i+1 两个位置的字符是不会被拆开的,所以可以直接记录两个连着的字符。然后为了直观的判断,只需要以没两个字符的第一个字符为第一个关键字,第二个字符为第二个关键字将原字符串排序,排序后的状态肯定可以通过翻转得到,所以排完序后只要存在两个相同,那么这两个就符合条件。
需要注意的是,只有两两之间才能删除,如果三个都可以,但是根据题意,在找到前两个后就被删了,因此不可能再匹配到第三个。
赋初值,要清零。
字符串(字母)的常用处理:转化为ASCII码记录。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 55 6 using namespace std; 7 struct pp{ 8 int one,two; 9 }; 10 pp s[maxn][maxn]; 11 int n,t,num[maxn],ans; 12 bool vis[maxn]; 13 const int comp(const pp&a,const pp&b) 14 { 15 if (a.one!=b.one) return a.one<b.one; 16 return a.two<b.two; 17 } 18 void chuli(int cur) 19 { 20 char c[maxn]; 21 scanf("%s",c+1); 22 int len=strlen(c+1); 23 num[cur]=len; 24 for (int i=1;i<=len/2;i++) 25 { 26 s[cur][i].one=min(c[i*2-1]-'a'+1,c[i*2]-'a'+1); 27 s[cur][i].two=max(c[i*2-1]-'a'+1,c[i*2]-'a'+1); 28 } 29 if (len%2) { 30 s[cur][len/2+1].one=c[len]-'a'+1; 31 s[cur][len/2+1].two=0; 32 } 33 sort(s[cur]+1,s[cur]+len/2+1,comp); 34 } 35 void work() 36 { 37 ans=n; 38 for (int i=1;i<=n;i++) 39 for (int j=i+1;j<=n;j++) 40 if (!vis[j]&&!vis[i]&&num[i]==num[j]){ 41 bool yes=false; 42 int l=num[i]; 43 if (l%2) l=l/2+1; 44 else l/=2; 45 for (int k=1;k<=l;k++) 46 if (s[i][k].one!=s[j][k].one||s[i][k].two!=s[j][k].two){ 47 yes=true;break; 48 } 49 if (yes) continue; 50 vis[i]=true;vis[j]=true; 51 ans-=2; 52 } 53 printf("%d ",ans); 54 } 55 int main() 56 { 57 freopen("kahuucino.in","r",stdin); 58 freopen("kahuucino.out","w",stdout); 59 cin>>t; 60 while(t) 61 { 62 memset(s,0,sizeof(s)); 63 memset(vis,0,sizeof(vis));//***** 64 scanf("%d",&n); 65 for (int i=1;i<=n;i++) 66 chuli(i); 67 work(); 68 t--; 69 } 70 return 0; 71 }
第二题:
对于每只怪有两个值:战斗值和能力值。它们相互打,只有战斗值高X的打死战斗值低的Y,并且打死后的战斗值变为:自己原来的战斗值-Y的战斗值+Y的能力值。问战斗后,怪中战斗值+能力值最大能达到多少。(对于每一只怪,不一定要把剩下的怪打完,想打谁打谁)
解: 这道题先开始根本没有读懂,以为必须把所有怪打完。。这道题用贪心做。把怪分为战斗型(负责打)和能力型(负责被打,因为打它获得正的战斗值)两种,然后将能力型按战斗值排序,战斗型按战斗值+能力值sum排序。对于某一个战斗值,可以恰好把能力型的所有怪打完(因为边打的时候战斗值会变大),这个战斗值为 “底线pos,在战斗型中第一个超过这个pos的怪即ans,因为战斗型按sum排序,而ans为战斗值+能力值,对于大于攻击值pos的所有战斗型怪能从能力值怪中获得的收益是相同的,所以只需比较这个sum,最靠前的即ans。当然,还有一种情况,就是用能力型中战斗值最大的一只打所有能力型怪,也可以获得很大的收益,将两者相比较得到ans。
看来贪心还是不是很熟,排序很重要,怎么排,什么是最优解,满足什么条件,把这些都弄清楚,方法就出来了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 100005 6 #define ll long long 7 using namespace std; 8 ll n,idi,idj,pos,s; 9 struct pp{ 10 ll fight,val; 11 }; 12 pp abled[maxn]; 13 struct oo{ 14 ll fight,sum; 15 }; 16 oo attack[maxn]; 17 const ll comp1(const pp&a,const pp&b) 18 { 19 return a.fight<b.fight; 20 } 21 const ll comp2(const oo&a,const oo&b) 22 { 23 return a.sum>b.sum; 24 } 25 int main() 26 { 27 freopen("zyougamaya.in","r",stdin); 28 freopen("zyougamaya.out","w",stdout); 29 cin>>n; 30 for (int i=1;i<=n;i++) 31 { 32 ll u,v; 33 scanf("%I64d%I64d",&u,&v); 34 if (v>u) { 35 abled[++idi].fight=u;abled[idi].val=v-u; 36 } 37 else { 38 attack[++idj].fight=u;attack[idj].sum=v+u; 39 } 40 } 41 sort(abled+1,abled+1+idi,comp1); 42 sort(attack+1,attack+1+idj,comp2); 43 bool b=false; 44 for (int i=1;i<=idi;i++) 45 { 46 if (!b&&s+abled[i].val>=abled[idi].fight){ 47 pos=abled[i].fight; b=true; 48 } 49 s+=abled[i].val;//前缀和 50 } 51 ll ans1=0,ans2=0; 52 for (int i=1;i<=idj;i++) 53 if (attack[i].fight>=pos){ 54 ans1=s+attack[i].sum; 55 break; 56 } 57 ans2=s+abled[idi].fight*2; 58 printf("%I64d",max(ans1,ans2)); 59 return 0; 60 }
第三题:
有一个文件系统,支持7个操作:加入文件,加入文件夹,打开文件夹,删除文件,删除文件夹,回到上一个路径,输出当前路径的所有文件、文件夹。
解:
一看就是个模拟。乱搞就可以了。注意细节。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define maxn 105 6 using namespace std; 7 int q,cur=1,idx=1,p; 8 int tot,he[maxn],ne[maxn],to[maxn]; 9 struct pp{ 10 int typ,fa; 11 bool zai; 12 char na[maxn*2]; 13 }; 14 pp s[maxn]; 15 void add(int a,int b,int t) 16 { 17 tot++;to[tot]=b;ne[tot]=he[a];he[a]=tot; 18 s[b].fa=a;s[b].typ=t;s[b].zai=true; 19 } 20 void work1()//返回父路径 21 { 22 if (s[cur].fa) cur=s[cur].fa; 23 else printf("No parent directory! "); 24 } 25 void work2(char x[])//进入 文件夹 26 { 27 int len=strlen(x+1); 28 for (int i=he[cur];i;i=ne[i]) 29 if (s[to[i]].typ==2&&s[to[i]].zai){//wen jian jia 30 int l=strlen(s[to[i]].na+1); 31 if (l!=len) continue; 32 bool yes=false; 33 for (int j=1;j<=len;j++) 34 if (s[to[i]].na[j]!=x[j]) {yes=true; 35 break; 36 } 37 if (yes) continue; 38 cur=to[i]; 39 return ; 40 } 41 printf("No such directory! "); 42 } 43 void work3(char x[],int t)//找文件(夹),创文件(夹) 44 { 45 int len=strlen(x+1);bool have=false; 46 for (int i=he[cur];i;i=ne[i]) 47 if (s[to[i]].typ==t&&s[to[i]].zai){ 48 int l=strlen(s[to[i]].na+1); 49 if (l!=len) continue; 50 bool yes=false; 51 for (int j=1;j<=len;j++) 52 if (s[to[i]].na[j]!=x[j]) {yes=true; 53 break; 54 } 55 if (yes) continue; 56 have=true; 57 break; 58 } 59 if (!have) { 60 ++idx; 61 add(cur,idx,t); 62 for (int i=1;i<=len;i++) 63 s[idx].na[i]=x[i]; 64 } 65 else{ 66 if (t==1) printf("File already exists! "); 67 else printf("Directory already exists! "); 68 } 69 } 70 void work4(char x[],int t)//删除文件或文件夹 71 { 72 int len=strlen(x+1);bool have=false; 73 for (int i=he[cur];i;i=ne[i]) 74 if (s[to[i]].typ==t&&s[to[i]].zai){ 75 int l=strlen(s[to[i]].na+1); 76 if (l!=len) continue; 77 bool yes=false; 78 for (int j=1;j<=len;j++) 79 if (s[to[i]].na[j]!=x[j]) {yes=true; 80 break; 81 } 82 if (yes) continue; 83 have=true; 84 s[to[i]].zai=false; 85 return ; 86 } 87 if(t==1) printf("No such file! "); 88 else printf("No such directory! "); 89 } 90 void print(int x) 91 { 92 if (!s[x].zai) return ; 93 if (s[x].typ==1){ 94 printf("%s ",s[x].na+1); 95 cout<<"<F>"<<endl; 96 } 97 else { 98 printf("%s ",s[x].na+1); 99 cout<<"<D>"<<endl; 100 } 101 } 102 void work7(int pi)//ls 输出 递归 103 { 104 int now=to[pi]; 105 if (ne[pi]==0) { 106 print(now); 107 return ; 108 } 109 work7(ne[pi]); 110 print(now); 111 } 112 int main() 113 { 114 freopen("nacumegu.in","r",stdin); 115 freopen("nacumegu.out","w",stdout); 116 cin>>q; 117 while (q) 118 { 119 char op[10],name[maxn*2]; 120 scanf("%s",op); 121 if (op[0]=='l'){ 122 p=he[cur]; 123 work7(p); 124 q--;//*** 125 continue;//*** 126 } 127 scanf("%s",name+1); 128 if (op[0]=='c'){ 129 if (name[1]=='.') 130 work1(); 131 else 132 work2(name); 133 } 134 else if(op[0]=='t') work3(name,1); 135 else if (op[0]=='r'){ 136 if (strlen(op)==2) 137 work4(name,1); 138 else 139 work4(name,2); 140 } 141 else if (op[0]=='m') work3(name,2); 142 q--; 143 } 144 return 0; 145 }