XJOI网上同步训练DAY1 T3

Posted GFY

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XJOI网上同步训练DAY1 T3相关的知识,希望对你有一定的参考价值。

思路:一开始看到这题的时候想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 }

 

以上是关于XJOI网上同步训练DAY1 T3的主要内容,如果未能解决你的问题,请参考以下文章

XJOI网上同步训练DAY3 T2

XJOI网上同步训练DAY6 T1

noip2016 Day1T3

XJOI模拟训练22

XJOI2018提高组训训练23

XJOI 郎思轲模拟题