SRM 551 DIV2
250pt
题意:
给定字符串,求使至多有一对相邻字符不同的排列数。
分析:
至多有一对就说明至多只有两种字符,答案只可能是0(多于两种字符),1(一种字符),2(两种字符)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdlib> #include <cctype> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <string> #include <iostream> #include <sstream> #include <map> #include <set> #include <queue> #include <stack> #include <fstream> #include <iomanip> #include <bitset> #include <list> #include <strstream> using namespace std; #define REP(i,n) for(i=0;i<(n);++i) #define FOR(i,l,h) for(i=(l);i<=(h);++i) #define FORD(i,h,l) for(i=(h);i>=(l);--i) typedef vector<int> VI; typedef vector<double> VD; typedef long long LL; class ColorfulBricks { public: int countLayouts(string b) { int i,j,n=b.length(); sort(b.begin(),b.end()); for(i=1,j=0;i<n;i++) if(b[i]!=b[i-1]) j++; if(j>1) return 0; return j?2:1; } };
500pt
题意:
给定一个字符串,字符串中交换相邻两个字符称为一次交换,求在至多m次交换后,只有一种字符的子串最大值。
分析:
若已求出答案,则在答案中,至少有一个字符是没有通过交换得到的,所以可以通过枚举那个位置不变的字符来暴力模拟左右相同字符的交换。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdlib> #include <cctype> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <string> #include <iostream> #include <sstream> #include <map> #include <set> #include <queue> #include <stack> #include <fstream> #include <iomanip> #include <bitset> #include <list> #include <strstream> using namespace std; #define REP(i,n) for(i=0;i<(n);++i) #define FOR(i,l,h) for(i=(l);i<=(h);++i) #define FORD(i,h,l) for(i=(h);i>=(l);--i) typedef vector<int> VI; typedef vector<double> VD; typedef long long LL; class ColorfulChocolates { public: int maximumSpread(string c, int m) { int i,j,k,cnt,ret,t,l,r,n=c.length(); ret=0; for(i=0;i<n;i++) { string s(c); cnt=0; for(t=1,l=i-1,r=i+1;;) { for(j=i-1;j>=0;j--) if(s[j]==s[i]) break; for(k=i+1;k<n;k++) if(s[k]==s[i]) break; if(k==n&&j<0) break; if(j<0) j=-111; if(k==n) k=111; if(k-r<l-j) { s[k]='-'; cnt+=k-r; r++; } else { s[j]='-'; cnt+=l-j; l--; } if(cnt>m) break; t++; } ret=max(ret,t); } return ret; } };
1000pt
题意:
给定三种颜色红绿蓝的数量,求相邻颜色不同的环排列数。
分析:
枚举首尾位置来分别递推,总共有六种。f[i][j][k][s]表示i个红色j个绿色k个蓝色末尾是s(0是红,1是绿,2是蓝)的排列数,求六次f[][][][]。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdlib> #include <cctype> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <string> #include <iostream> #include <sstream> #include <map> #include <set> #include <queue> #include <stack> #include <fstream> #include <iomanip> #include <bitset> #include <list> using namespace std; #define REP(i,n) for(i=0;i<(n);++i) #define FOR(i,l,h) for(i=(l);i<=(h);++i) #define FORD(i,h,l) for(i=(h);i>=(l);--i) typedef vector<int> VI; typedef vector<double> VD; typedef long long LL; const int MOD=1000000007; class ColorfulCupcakesDivTwo { public: int n,f[26][26][26][3]; int cal(int i ,int j, int k, int s) { int &ret=f[i][j][k][s]; if(ret>-1) return ret; ret=0; if(s==0) { if(i>0) ret=(cal(i-1,j,k,1)+cal(i-1,j,k,2))%MOD; } else if(s==1) { if(j>0) ret=(cal(i,j-1,k,0)+cal(i,j-1,k,2))%MOD; } else { if(k>0) ret=(cal(i,j,k-1,0)+cal(i,j,k-1,1))%MOD; } return ret; } int countArrangements(string cupcakes) { int i,j,ret,a[3]={0}; n=cupcakes.length(); for(i=0;i<n;i++) if(cupcakes[i]>='A'&&cupcakes[i]<='C') a[cupcakes[i]-'A']++; for(i=0;i<3;i++) if(a[i]>n/2) return 0; ret=0; for(i=0;i<3;i++) for(j=0;j<3;j++) if(i!=j) { memset(f,-1,sizeof(f)); for(int k=0;k<3;k++) f[1][0][0][k]=f[0][1][0][k]=f[0][0][1][k]=0; if(a[i]*a[j]) { if(i==0) f[1][0][0][0]=1; else if(i==1) f[0][1][0][1]=1; else f[0][0][1][2]=1; ret=(ret+cal(a[0],a[1],a[2],j))%MOD; } } return ret; } };