思路:一开始看到这题的时候想DP,可是发现貌似不行。。因为有前缀也有后缀,而且有的后缀会覆盖到现在的前缀,这就不满足无后效性了啊!
但是有个很巧妙的思路:如果我们知道a[i]的最大值,那么p的数量和q的数量也确定了。所以序列长度也确定了,设m为序列长度。
而且对于每个a[i]都代表了一个固定数量的p和q和长度。
因此,长度大于m/2的前缀,我们可以用总的p和总的q减去它,转换成小于等于m/2长度的前缀后缀。
这样我们可以设计DP为f[i][j][k],代表从左往右i个中有j个p,从右往左i个有k个p,这样f[(m+1)/2]的位置就是最终答案!
注意要记录一个pre数组记录这个状态的最优解是从哪个位置转移过来的。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #define ll long long 7 ll a[200005]; 8 const ll PW=9705276; 9 const ll QW=12805858; 10 int c[200005][2],n,pre[205][205][205][2],w[205][205],f[205][205][205]; 11 int ans[200005],cn; 12 int read(){ 13 char ch=getchar();int t=0,f=1; 14 while (ch<'0'||'9'<ch){if (ch=='-') f=-1;ch=getchar();} 15 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 16 return t*f; 17 } 18 void init(){ 19 n=read(); 20 for (int i=0;i<n;i++){ 21 double x;scanf("%lf",&x); 22 a[i]=(ll)(x*100000+0.5); 23 } 24 } 25 void solve(){ 26 int mxpos=0; 27 for (int i=1;i<n;i++){ 28 if (a[i]>a[mxpos]) mxpos=i; 29 } 30 int totp=-1,totq=-1; 31 for (int i=0;(ll)i*PW<=a[mxpos];i++) 32 if ((a[mxpos]-(ll)i*PW)%QW==0){ 33 totp=i; 34 totq=(int)((a[mxpos]-(ll)i*PW)/QW); 35 break; 36 } 37 for (int i=0;i<n;i++){ 38 int p=-1,q=-1; 39 for (int j=0;(ll)j*PW<=a[i];j++) 40 if ((a[i]-(ll)j*PW)%QW==0){ 41 p=j; 42 q=(int)((a[i]-(ll)j*PW)/QW); 43 break; 44 } 45 if (p!=-1&&p+q<=totp+totq){ 46 c[cn][0]=p; 47 c[cn][1]=q; 48 cn++; 49 } 50 } 51 int m=totp+totq; 52 for (int i=0;i<cn;i++){ 53 if (c[i][0]+c[i][1]<=m/2){ 54 w[c[i][0]+c[i][1]][c[i][1]]++; 55 }else{ 56 w[m-c[i][0]-c[i][1]][totq-c[i][1]]++; 57 } 58 } 59 f[0][0][0]=0; 60 for (int i=1;i<=m/2;i++) 61 for (int j=0;j<=i;j++) 62 for (int k=0;k<=i;k++){ 63 int s=-1; 64 for (int p=0;p<=1;p++){ 65 for (int q=0;q<=1;q++){ 66 if (j-p>=0&&j-p<i&&k-q>=0&&k-q<i&&f[i-1][j-p][k-q]>s){ 67 s=f[i-1][j-p][k-q]; 68 pre[i][j][k][0]=p; 69 pre[i][j][k][1]=q; 70 } 71 } 72 } 73 f[i][j][k]=s+w[i][j]+((k==j)?0:w[i][k]); 74 } 75 int ansi=-1,ansj=-1,ansk=-1; 76 for (int k=0;k<=m%2;k++) 77 for (int i=0;i<=m/2;i++){ 78 int j=totq-k-i; 79 if (j>=0&&j<=m/2&&(ansi==-1||f[m/2][i][j]>f[m/2][ansi][ansj])){ 80 ansi=i; 81 ansj=j; 82 ansk=k; 83 } 84 } 85 if (m%2) ans[m/2]=ansk; 86 for (int i=m/2;i>0;i--){ 87 int p=pre[i][ansi][ansj][0]; 88 int q=pre[i][ansi][ansj][1]; 89 ans[i-1]=p; 90 ans[m-i]=q; 91 ansi-=p; 92 ansj-=q; 93 } 94 for (int i=0;i<m;i++) 95 if (ans[i]) printf("Q"); 96 else printf("P"); 97 } 98 int main(){ 99 init(); 100 solve(); 101 }