zoukankan      html  css  js  c++  java
  • hdu 4901 The Romantic Hero (dp)

    题目链接

    题意:给一个数组a,从中选择一些元素,构成两个数组s, t,使s数组里的所有元素异或

    等于 t数组里的所有元素 位于,求有多少种构成方式。要求s数组里 的所有的元素的下标

    小于 t数组里的所有的元素的下标。

    分析:比赛的时候,刚开始脑子很乱,后来想了一下思路也敲了,发现自己的程序结果不对

    自己一点一点计算后发现自己的程序有一部分计算重复了,其实还是dp的思路不够清晰。

    d[i][j]代表第i个数 新产生的结果为数字 j 的个数。

    AC代码:

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <cmath>
     5 #include <cstdio>
     6 #include <set>
     7 #include <vector>
     8 #include <algorithm>
     9 #define LL long long
    10 const int maxn = 1000+50;
    11 const int mo = 1000000000+7;
    12 using namespace std;
    13 __int64 cnt;
    14 int n, a[maxn];
    15 __int64 d[maxn][maxn], dt[maxn][maxn], temp[maxn][maxn];
    16 
    17 int main()
    18 {
    19     int T, i, j, x;
    20     scanf("%d", &T);
    21     while(T--)
    22     {
    23         cnt = 0;
    24         memset(d, 0, sizeof(d));
    25         memset(dt, 0, sizeof(dt));
    26         memset(temp, 0, sizeof(temp));
    27         scanf("%d", &n);
    28         for(i = 0; i < n; i++)
    29         scanf("%d", &a[i]);
    30         for(i = 0; i < n; i++)
    31         {
    32             for(j = 0; j < 1025; j++)
    33             {
    34                 if(i!=0 && temp[i-1][j])  //让之前存在的和a[i]异或会产生新的存放在d数组里
    35                 {
    36                     x = (a[i]^j);    //x有可能会大于j,所以不能用d数组直接累加
    37                     d[i][x] += temp[i-1][j];
    38                 }
    39                 d[i][j] %= mo;  //随时取余很重要,不然会wa
    40             }
    41             d[i][a[i]] ++;  //加上自身
    42             for(j = 0; j < 1025; j++)
    43             {
    44                 if(i != 0)
    45             temp[i][j] += temp[i-1][j] + d[i][j];  //temp数组用来维护目前所有的
    46             else                                   //结果,并且不可以用d直接加,否则会重复
    47             temp[i][j] = d[i][j];
    48             temp[i][j] %= mo;
    49             }
    50         }
    51         memset(temp, 0, sizeof(temp));
    52         for(i = n-1; i >= 0; i--)
    53         {
    54             for(j = 0; j < 1025; j++)
    55             {
    56                 if(temp[i+1][j])
    57                 {
    58                     x = (a[i]&j);
    59                     dt[i][x] += temp[i+1][j];
    60                 }
    61                 dt[i][j] %= mo;
    62             }
    63             dt[i][a[i]] ++;
    64             for(j = 0; j < 1025; j++)
    65             {
    66                 temp[i][j] += temp[i+1][j] + dt[i][j];
    67                 temp[i][j] %= mo;
    68             }
    69         }
    70         for(i = n-2; i >= 0; i--)
    71         for(j = 0; j < 1025; j++)
    72         {
    73             dt[i][j] += dt[i+1][j];  //这是防止重复的,让dt数组累加,d数组不累加。
    74             dt[i][j] %= mo;
    75         }
    76 
    77         for(i = 0; i < n-1; i++)
    78             for(j = 0; j < 1025; j++)
    79             {
    80                 cnt += d[i][j]*dt[i+1][j];  //用前面的乘以后面的
    81                 cnt %= mo;
    82             }
    83         cnt %= mo;
    84         printf("%I64d
    ", cnt);
    85     }
    86     return 0;
    87 }

    顺便贴一下自己在比赛中wa的代码,思路不清。

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <cmath>
     5 #include <cstdio>
     6 #include <set>
     7 #include <vector>
     8 #include <algorithm>
     9 #define LL long long
    10 const int maxn = 1000+50;
    11 const int mo = 1000000000+7;
    12 using namespace std;
    13 __int64 cnt, f[maxn];
    14 int n, a[maxn];
    15 __int64 d[maxn][maxn], dt[maxn][maxn];
    16 
    17 int main()
    18 {
    19     int T, i, j, tmp;
    20     scanf("%d", &T);
    21     while(T--)
    22     {
    23         cnt = 0;
    24         memset(d, 0, sizeof(d));
    25         memset(dt, 0, sizeof(dt));
    26         memset(a, 0, sizeof(a));
    27         memset(f, 0, sizeof(f));
    28         scanf("%d", &n);
    29         for(i = 0; i < n; i++)
    30             scanf("%d", &a[i]);
    31         d[0][a[0]] = 1;
    32         f[a[0]] = 1;
    33         for(i = 1; i < n; i++)
    34         {
    35             for(j = 0; j < 1025; j++)
    36             {
    37                 if(f[j])
    38                 {
    39                     tmp = (a[i]^j);
    40                     d[i][tmp] += f[j];
    41                 }
    42                 d[i][j] %= mo;
    43             }
    44             d[i][a[i]] ++;
    45             f[a[i]] ++;
    46         }
    47 
    48         memset(f, 0, sizeof(f));
    49         dt[n-1][a[n-1]] = 1;
    50         f[a[n-1]] = 1;
    51         for(i = n-2; i >= 0; i--)
    52         {
    53             for(j = 0; j < 1025; j++)
    54             {
    55                 if(f[j])
    56                 {
    57                     tmp = (a[i]&j);
    58                     dt[i][tmp] += f[j];
    59                 }
    60                 d[i][j] %= mo;
    61             }
    62             dt[i][a[i]] ++;
    63             f[a[i]] ++;
    64         }
    65 
    66         for(i = n-2; i >= 0; i--)
    67         for(j = 0; j < 1025; j++)
    68         {
    69             dt[i][j] += dt[i+1][j];
    70             dt[i][j] %= mo;
    71         }
    72 
    73         for(i = 0; i < n-1; i++)
    74             for(j = 0; j < 1025; j++)
    75             {
    76                 cnt += d[i][j]*dt[i+1][j];
    77                 cnt %= mo;
    78             }
    79         cnt %= mo;
    80         printf("%I64d
    ", cnt);
    81     }
    82     return 0;
    83 }
  • 相关阅读:
    Freemarker与Springmvc
    Freemarker与普通java
    Freemarker与Servlet
    跳舞的时间插件
    video标签播放视频
    字符串反转
    菲波拉契数列
    求所有子数组的和的最大值
    Spring AOP 5种通知与java动态代理
    线程维护日志队列
  • 原文地址:https://www.cnblogs.com/bfshm/p/3884471.html
Copyright © 2011-2022 走看看