zoukankan      html  css  js  c++  java
  • hdu CA Loves GCD(dp)

    一道我想骂人的题,差点把我气炸了。

    题意:

    求一个数的集合中(非多重集,每个数只出现一次)所有子集的gcd的和。结果MOD10^8+7输出。

     

    输入输出不说了,自己看吧,不想写了。

     

    当时我真把它当作数论题来写了,以为可以推导出什么公式然后化简大量重复的操作的。结果最后也没找到。最后题解说是dp,我同学说是暴力,吐血10升。

    然后弄出来dp方程之后还是反复的wa,方程明明没啥问题,愣是卡了2个小时找不出错误,心情烦躁的要命,坑爹的室友还各种看视频打游戏,还不带耳机,我自己只好带着耳机大声放音乐,最后连音乐都听不下去了,恶心的想吐。

    后来实在无奈了查了下题解,但是没人用dp写,有个用莫比乌斯反演的orz,还有个用暴力的,不过其实有dp的思想在里面。当然这不重要,重要的是我看见了他MOD加的位置挺有意思的,然后猛然想到我的int爆了!因为需要一个小于10^8的数×一个小于1000的数,这个数有可能爆!我叉!特么这不是故意卡int的意思吗?最后把这个改了终于过了……此时距离比赛结束已经5个小时了,我*!

     

    状态转移方程:

    dp[i][a[i]] += 1;

    dp[i][j] += dp[i-1][j];

    dp[i][gcd[j][a[i]]] += dp[i-1][j];

    其中gcd[][]是预处理离线出来的,要不然可能会超时。

    状态dp[i][j]表示在前n个数的集合中,gcd为j的集合有多少个。

    方程表示三种情况:

    1. 只有a[i]的集合。
    2. 不存在a[i],只存在前i-1个数中若干数的集合。
    3. 存在a[i],且存在前i-1个数中若干数的集合。

    时间复杂度为O(n*maxn),其中maxn为a[]数组中的最大值。

    具体见代码——

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 #define LL long long
     7 
     8 const int N = 1010;
     9 const int Mod = 100000007;
    10 
    11 int a[N];
    12 LL dp[N][N];
    13 int gcd[N][N];
    14 int t, n;
    15 
    16 int Gcd(int x, int y)
    17 {
    18     if(x < y)
    19     {
    20         int t = x;
    21         x = y;
    22         y = t;
    23     }
    24     while(y != 0)
    25     {
    26         int t = y;
    27         y = x%y;
    28         x = t;
    29     }
    30     return x;
    31 }
    32 
    33 void Table()
    34 {
    35     for(int i = 1; i < 1005; i++)
    36     {
    37         for(int j = 1; j <= i; j++)
    38         {
    39             gcd[i][j] = gcd[j][i] = Gcd(i, j);
    40         }
    41     }
    42 }
    43 
    44 int main()
    45 {
    46     //freopen("test.in", "r", stdin);
    47     Table();
    48     scanf("%d", &t);
    49     for(int tm = 1; tm <= t; tm++)
    50     {
    51         scanf("%d", &n);
    52         int maxn = 0;
    53         for(int i = 0; i < n; i++)
    54         {
    55             scanf("%d", &a[i]);
    56             maxn = maxn > a[i] ? maxn : a[i];
    57         }
    58         memset(dp, 0, sizeof(dp));
    59         dp[0][a[0]] = 1;
    60         for(int i = 1; i < n; i++)
    61         {
    62             dp[i][a[i]] += 1;                                       //转移方程1
    63             for(int j = 1; j <= maxn; j++)
    64             {
    65                 dp[i][j] += dp[i-1][j];                             //转移方程2
    66                 dp[i][gcd[j][a[i]]] += dp[i-1][j];                  //转移方程3
    67                 dp[i][j] %= Mod;
    68                 dp[i][gcd[j][a[i]]] %= Mod;
    69             }
    70         }
    71         int ans = 0;
    72         for(int i = 1; i <= maxn; i++)
    73         {
    74             ans += (dp[n-1][i]*i)%Mod;                  //这里小心dp如果是int可能会爆
    75             ans %= Mod;
    76         }
    77 
    78         printf("%d
    ", ans);
    79     }
    80     return 0;
    81 }
    View Code

    自己确实挺弱的,还需要努力,但是今天确实非常烦!所有认为这些没什么好烦的,都是因为他没有身临其境的感觉。

  • 相关阅读:
    android中接口和抽象类的区别
    最靠谱的禁止ViewPager滑动方法
    Android Studio 自定义属性,命名空间
    代码设置Android EditText的相关问题。输入长度maxLength
    关于Android中,保留小数点后两位的方式
    Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
    既然安卓免费,那 Google 是靠什么赚钱的?
    android viewconfiguration
    Android中实现为TextView添加多个可点击的文本
    Textview解析带图片的html示例
  • 原文地址:https://www.cnblogs.com/mypride/p/5348742.html
Copyright © 2011-2022 走看看