usaco 4.3 Buy Low, Buy Lower 动态规划

典型的动态规划,难点是第二步,cnt[i]表示以a[i]结尾的最长下降序列的种数,则
cnt[i] = count( len[k]+1==len[i]), 1<=k < i , 其中len[i]表示以a[i]结尾的最长下降子序列长度

 

还有一个问题,如果生成的实际序列值相等,则算作一种,可以通过一下方法处理:
计算出a[i]之后和第一个和a[i]相等的数a[k],令next[i] = k; 如果没有相等的则next[i] = 0
计数时如果 next[j]!=0 && next[j] < i ,则不累计,因为位于j和i之间的数里存在和a[i]相等的,从而可以以a[next[j]]替换a[j]来得

到相同的序列; 同时,累加的过程是指数级增长的,所以要用高精度

 

  1. /*
  2. PROG: buylow
  3. LANG: C++
  4. ID: heben991
  5. */
  6. #include <iostream>
  7. #include <algorithm>
  8. using namespace std;


  9. const int N = 6000, R = 10000, L = 250;


  10. int len[N], a[N], next[N];

  11. struct bignum
  12. {
  13.     int a[L];
  14.     int n;
  15.     bignum operator = (int b)
  16.     {
  17.         memset(a,0,sizeof(a));
  18.         n = 1;
  19.         a[1] = b;
  20.     }
  21.     bignum operator = (const bignum &b)
  22.     {
  23.         memset(a,0,sizeof(a));
  24.         for(int i = 1; i <= b.n; ++i) a[i] = b.a[i];
  25.         n = b.n;
  26.     }

  27.     void print()
  28.     {
  29.         int i;
  30.         printf("%d", a[n]);
  31.         for(i = n-1; i >= 1; --i) printf("%04d", a[i]);
  32.     }
  33. }cnt[N];

  34. bignum operator + (bignum &a, bignum &b)
  35. {
  36.     bignum c;
  37.     int i, len=max(a.n,b.n);
  38.     c = 0;
  39.     for(i = 1; i <= len; ++i)
  40.     {
  41.         c.a[i] += a.a[i] + b.a[i];
  42.         if(c.a[i] >= R)
  43.         {
  44.             c.a[i+1] += c.a[i]/R;
  45.             c.a[i] -= R;
  46.         }
  47.     }
  48.     if(c.a[len+1]!=0) c.n=len+1;
  49.     else c.n=len;
  50.     return c;
  51. }


  52. int main()
  53. {

  54.     int i, j, k, t, n;

  55.     freopen("buylow.in","r",stdin);
  56.     freopen("buylow.out","w",stdout);

  57.     scanf("%d", &n);
  58.     for(i = 1; i <= n; ++i) scanf("%d",a+i);
  59.     a[++n] = 0;

  60.     for(i = 1; i <= n; ++i)
  61.     {
  62.         for(j = i+1; j <= n; ++j)
  63.         {
  64.             if(a[i]==a[j])
  65.             {
  66.                 next[i] = j;
  67.                 break;
  68.             }
  69.         }
  70.     }

  71.     for(i = 1; i <= n; ++i)
  72.     {
  73.         len[i] = 1;
  74.         cnt[i] = 1;
  75.         for(j = 1; j < i; ++j)
  76.         {
  77.             if(next[j] && next[j] < i) continue;

  78.             if(a[i] < a[j])
  79.             {
  80.                 if(len[j]+1 > len[i])
  81.                 {
  82.                     len[i] = len[j]+1;
  83.                     cnt[i]=0;
  84.                     cnt[i]=cnt[j];
  85.                 }
  86.                 else if(len[j]+1 == len[i])
  87.                 {
  88.                     cnt[i]=cnt[i]+cnt[j];
  89.                 }
  90.             }
  91.         }
  92.     }

  93.     printf("%d ", len[n]-1);
  94.     cnt[n].print();
  95.     puts("");
  96.     return 0;
  97. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值