题目链接:https://www.codechef.com/CHN17ROL/problems/MINSTR
题目大意是:给你一串ab串(只有a,b,ab,ba,aa,bb六种情况),然后串之间相互组合,若相邻的字母相同则只保留一个字母,问最终可以把字符串缩短到最小是多少个字母。
em...感觉啊三的icpc题目读起来比较简单,不过可能也因为是送分题吧(也只能做送分题了......)。
思路:首先记录每一种字符串(上面的6种)出现的次数,然后如果有ab ba这样的就只用保留ab ba两种的总数,(因为aa==a,bb==b,然后它们又可以与ab或ba消掉,所以无论如何只剩下ab或ba),然后就再让ab ba合并,每一个ab ba合并脱掉一个字母(可以形成aba或bab,任意的它们都可以与ab或ba组合),同时合并得出的又可以相互合并(一组合并脱掉一个字母),最后这里要注意一下:开始以为任意的ab都可以无限与组合起来的一大串合并,后来起床想了想,发现只能合一个,之和就不能合了(如:aba+ab=abab不能继续和ab合)
ac代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
const int maxn=1e5+50;
long long d[maxn],cntaa,cntab,cntba,cntbb,cnta,cntb,cnt,rest,temp,ans,sum;
int t,n;
char s[3];void init(){memset(d,0,sizeof(d));d[2]=1;///打表记录任意n个组合之间脱掉的单词for(int i=3;i<=maxn;i++){if(i%2)d[i]=d[i-1]+1;elsed[i]=d[2]+d[i-2]+1;}
}int main(){init();while(scanf("%d",&t)!=EOF){for(int i=0;i<t;i++){cntaa=cntbb=cntab=cntba=cnta=cntb=cnt=0;///计数器scanf("%d",&n);for(int j=0;j<n;j++){memset(s,0,sizeof(s));scanf("%s",s);if(s[0]=='a'&&s[1]=='b')cntab++;else if(s[0]=='b'&&s[1]=='a')cntba++;else if(s[0]=='a'&&(s[1]=='\0'||s[1]=='a'))cnta++;else if(s[0]=='b'&&(s[1]=='\0'||s[1]=='b'))cntb++;}if(!cntba&&!cntab){if(cnta) cnt++;if(cntb) cnt++;}else if((cntab&&!cntba))cnt+=cntab<<1;else if(!cntab&&cntba)cnt+=cntba<<1;else{sum=(cntab+cntba)<<1;///4if(cntab<=cntba){temp=cntab;///1rest=cntba-cntab;///0}else{temp=cntba;rest=cntab-cntba;}ans=d[temp]+temp;cnt=sum-ans;if(rest)cnt--;}printf("%lld\n",cnt);}}return 0;
}