zoukankan      html  css  js  c++  java
  • 【hdu多校联考第二场】Odd Shops

    Description

      这道题的题意是这道难读,大概就是给你n个商店,每个商店的重量为i的商品用ai表示,对于任意商店的a数列都是相同的,重量的范围为[1,10]

      求购买方案总数为奇数的重量一共有多少种,答案取膜998244353

    Input Format

      多组数据,每组数据第一行一个整数n表示一共有n个商店,第二行10个整数表示数列a

    Output Format

      对于每组数据输出一行表示答案

    Sample Input

      1

      1 2 3 4 5 6 7 8 9 10

      2

      1 0 0 0 0 0 0 0 0 0

      100

      1 1 1 1 0 0 0 0 0 0

    Sample Output

      6
      2
      35

     Solution

    打算学习一下god们的题解风格

     

    这道题目,首先答案显然为${(1 + sumlimits_{i = 1}^{10} {{a_i}*{x^i}} )^n}$中系数为奇数的项有几个

     

    那么我们只要对该式进行处理就行了

     

    首先我们设关注到题目要求统计的是系数为奇数,那么相当于在mod 2意义下进行运算

     

    我们现在来考虑一个子问题,$f{left( n ight)^{2k}}*gleft( n ight)$中有几个系数为奇数

     

    对于该式,我们意识到前一个式子是${(f{left( n ight)^k})^2}$因为是平方,所以打开之后两项相乘的系数就会消掉

     

    例如${left( {a + b} ight)^2} = {a^2} + {b^2} + 2ab$最后一项对答案显然没有贡献,也就是说平方后我们关心的只是一个与原串相同的串

     

    对于g(n),我们将其拆分成g(n)=o(n)+e(n),o(n)为g(n)中奇数次方的项,e(n)为g(n)中偶数次方的项,由于${(f{left( n ight)^k})^2}$只剩下平方项,所以o(n)与e(n)对答案的贡献是独立的

     

    那么最后一步就是递归拆分后递归求解这个问题,顺便加个map瞎记忆化一下就过了

     

    为什么我们要进行这个拆分呢?

     

    我们可以很快发现这样拆分之后递归求解的时候o(n)和e(n)的项数就可以从20降为10,这样就可以将一个${10^{10}}$项的多项式希望得到的结果,只用10位的二进制数得到答案

     

    题解是这么想,代码也确实是这么打,但是这个代码还是比较巧妙的(我本来以为要fft的,后来看了标程才明白,确实我觉得不用开ll,大家可以尝试一下)

     

    代码啦~~~

    #include<cstdio>
    #include<map>
    #include<algorithm>
    #define ll long long 
    using namespace std;
    map<pair<ll,ll>,ll> mp;
    ll mo=998244353,x;
    ll mul(ll a,ll b){
        ll ret=0;
        while (b){
            ret^=a*(b&(-b)),b-=b&(-b);
        }
        return ret;
    }
    ll f(ll n,ll g){
        if (mp.count(make_pair(n,g)))return mp[make_pair(n,g)];
        ll &ret=mp[make_pair(n,g)];
        if (!n)return ret=__builtin_popcountll(g)%mo;
        if ((n&1))g=mul(g,x);ll a=0,b=0;
        for (int i=0;i<=25;i++)if ((g&(1<<i))){
            if ((i&1))a|=(1<<(i>>1));
            else b|=(1<<(i>>1));
        }
        return ret=(f(n>>1,a)+f(n>>1,b))%mo;
    }
    int a[15],n;
    int main(){
        while (~scanf("%d",&n)){
            mp.clear();
            x=1;
            for (int i=1;i<=10;i++){
                scanf("%d",&a[i]);
                if ((a[i]&1))x|=(1<<i);
            }
            ll ans=f(n,1);
            printf("%d
    ",ans);
        }
    }

     

  • 相关阅读:
    C版程序语法 (消除左递归)
    文法
    201506110248 实验报告
    组合数据类型
    UBUNTU四种版本的区别【转】
    MFC对话框程序屏蔽回车与ESC键,Tab键
    std::fstream打开中文路径名失败的问题原因、解决方法以及注意事项
    前进。。。。。。
    程序员学习能力提升三要素[转]
    java学习推荐资源
  • 原文地址:https://www.cnblogs.com/Cool-Angel/p/9380809.html
Copyright © 2011-2022 走看看