topcoder srm 709 div1
1 给定一个长度为n的整数数组A,重排列数组A使得下面计算出的X最大:(n不大于15,A中的大于等于0小于等于50)
int X=0; for(int i=0;i<n;++i) X=X+(X^A[i]);
思路:因为抑或只用到了X的后6位,所以令f[i][j]表示已经使用的数字集合为i,得到的当前的X的后6位为j的X的最大值。
#include <iostream> #include <stdio.h> #include <vector> #include <map> #include <algorithm> #include <string> #include <string.h> #include <set> using namespace std; int f[1<<15][1<<6]; class Xscoregame { public: int getscore(vector <int> a) { const int n=(int)a.size(); memset(f,-1,sizeof(f)); f[0][0]=0; for(int i=0;i<(1<<n);++i) for(int k=0;k<(1<<6);++k) { const int X=f[i][k]; if(X==-1) continue; for(int j=0;j<n;++j) if(!(i&(1<<j))) { int y=X+(X^a[j]); int ni=i|(1<<j); int nk=y&63; if(f[ni][nk]<y) { f[ni][nk]=y; } } } int ans=0; for(int i=0;i<(1<<6);++i) { ans=max(ans,f[(1<<n)-1][i]); } return ans; } };
2 给定一个只包含小写a和b的主串S和K个只包含数字0,1,2,3的模式串。可以将主串中的a变成A,b变成B。其中,a可以匹配0,1,A可以匹配2,3,b可以匹配0,2,B可以匹配1,3。对于S中一个位置p和某个模式串i,f(p,i)=1当且仅当S从p开始可以完全匹配模式串i,否则f(p,i)=0。S经过一些位置的改变使得$\sum_{p=0}^{|S|-1}\sum_{i=0}^{K-1}f(p,i)$最大。其中K不大于5,S大小不大于50。
思路:记f[i][j][k]表示到S的第i个位置,能够匹配的最长的是第j个模式串,匹配的长度是k。因为可以从二元组(j,k)中确定S从i开始前面这一段所有的位置的信息,那么下一次就可以接着找出能匹配的最长的。
#include <iostream> #include <stdio.h> #include <vector> #include <map> #include <algorithm> #include <string> #include <string.h> #include <set> using namespace std; int f[55][5][55]; int check(char x,char y) { if(x=='a') return y=='0'||y=='1'; if(x=='A') return y=='2'||y=='3'; if(x=='b') return y=='0'||y=='2'; return y=='1'||y=='3'; } void up(int &x,int y) { if(y>x) x=y; } char get(char x,char y) { if(x=='a') { if(y=='0'||y=='1') return 'a'; return 'A'; } else { if(y=='0'||y=='2') return 'b'; return 'B'; } } vector<int> get(const int id,const int L,const int spos,const string& S,const vector<string> &a,const int tag) { int ans0=0,ans1=0; int nMax=0; string tmp=""; for(int i=1;i<=L;++i) { tmp+=get(S[spos-(L+1-i)],a[id][i-1]); } tmp+=tag?S[spos]-'a'+'A':S[spos]; for(int i=0;i<(int)a.size();++i) { string t=a[i]; for(int j=1;j<=(int)t.size()&&j<=(int)tmp.size();++j) { int ok=1; for(int x=0;x<j;++x) { if(!check(tmp[tmp.size()-(j-x)],t[x])) { ok=0; break; } } if(ok) { if(j>nMax) { nMax=j; ans1=i; } if(j==(int)t.size()) ++ans0; } } } return {ans0,ans1,nMax}; } class Softmatch { public: int count(string S,vector<string> a) { const int N=(int)S.size(); const int M=(int)a.size(); memset(f,-1,sizeof(f)); int cnt0=0,cnt1=0; for(int i=0;i<M;++i) { if(a[i].size()==1&&check(S[0],a[i][0])) ++cnt0; if(a[i].size()==1&&check(S[0]-'a'+'A',a[i][0])) ++cnt1; } for(int i=0;i<M;++i) { if(check(S[0],a[i][0])) { if(a[i].size()==1) f[0][i][1]=cnt0; else f[0][i][1]=0; } else if(check(S[0]-'a'+'A',a[i][0])) { if(a[i].size()==1) f[0][i][1]=cnt1; else f[0][i][1]=0; } else f[0][i][0]=0; } for(int i=1;i<N;++i) { for(int j=0;j<M;++j) for(int k=0;k<=(int)a[j].size();++k) { if(f[i-1][j][k]==-1) continue; for(int p=0;p<2;++p) { vector<int> t=get(j,k,i,S,a,p); up(f[i][t[1]][t[2]],f[i-1][j][k]+t[0]); } } } int ans=0; for(int i=0;i<M;++i) for(int j=0;j<=(int)a[i].size();++j) { up(ans,f[N-1][i][j]); } return ans; } };
3 给定一个长度为n的整数数组A(n不大于50且n为偶数)。构造出一个只包含左右圆括号的长度为n的字符串S,使得字符串满足(1)左右括号匹配;(2)对于任意两个位置i,j,若A[i]=A[j],那么必须S[i]=S[j]。问这样的字符串有多少个。
思路:将字符串分成左右两部分。总的思路是,最后左边剩余的左括号等于右边剩余的右括号数。所以对于那么只在左半部分或者右半部分的数字可以随意指定它是左括号还是右括号;对于那些在两边都出现的数字,左边的这些数字出现为左括号的在右半部分必须为右括号。
#include <iostream> #include <stdio.h> #include <vector> #include <map> #include <algorithm> #include <string> #include <string.h> #include <set> using namespace std; int Mask[1<<25]; class ColorfulParentheses { vector<int> c; int n; int mp[55],nId; vector<int> S[2][26]; void dfs(int dep,int num,int tag,long long open,long long close) { if(dep==n) { S[tag][num].push_back(open&((1ll<<nId)-1)); return; } if(tag) { int t=mp[c[dep]]; if(!(close&(1ll<<t))) dfs(dep+1,num+1,tag,open|1ll<<t,close); if(num&&!(open&(1ll<<t))) dfs(dep+1,num-1,tag,open,close|(1ll<<t)); } else { int t=mp[c[n*2-1-dep]]; if(!(open&(1ll<<t))) dfs(dep+1,num+1,tag,open,close|1ll<<t); if(num&&!(close&(1ll<<t))) dfs(dep+1,num-1,tag,open|1ll<<t,close); } } public: long long count(vector<int> color) { c=color; n=(int)c.size()>>1; nId=0; int L[55],R[55]; memset(L,0,sizeof(L)); memset(R,0,sizeof(R)); for(int i=0;i<n;++i) ++L[c[i]],++R[c[i+n]]; for(int i=0;i<n;++i) { if(L[c[i]]&&R[c[i]]) mp[c[i]]=nId++; } for(int i=0,t0=0,t1=0;i<n;++i) { if(L[c[i]]&&0==R[c[i]]) mp[c[i]]=nId+(t0++); if(0==L[c[i+n]]&&R[c[i+n]]) mp[c[i+n]]=nId+(t1++); } dfs(0,0,0,0,0); dfs(0,0,1,0,0); long long ans=0; for(int i=0;i<=n;++i) { for(int j=0;j<(int)S[0][i].size();++j) ++Mask[S[0][i][j]]; for(int j=0;j<(int)S[1][i].size();++j) ans+=Mask[S[1][i][j]]; for(int j=0;j<(int)S[0][i].size();++j) --Mask[S[0][i][j]]; } return ans; } };