• 51nod 1684 子集价值


    lyk最近在研究位运算。

    它发现除了xor,or,and外还有很多运算。

    它新定义了一种运算符“#”。

    具体地,可以由4个参数来表示。

     ai,j

    其中i,j与a的值均∈[0,1]。

    当然问题可以扩展为>1的情况,具体地,可以将两个数分解为p位,然后对于每一位执行上述的位运算,再将这个二进制串转化为十进制就可以了。

    例如当 a0,0=a1,1=0,a0,1=a1,0=1,3#4在p=3时等于7,2#3在p=4时等于1(实际上就是异或运算)。

    现在lyk想知道的是,已知一个数列b。

    它任意选取一个序列c,满足 c1<c2<...<ck1c1ckn ,这个序列的价值为 bc1 # bc2 #...# bck 的平方。

    这里我们假设k是正整数,因此满足条件的c的序列一定是 2n1 。lyk想知道所有满足条件的序列的价值总和是多少。

    例如样例中,7个子集的价值分别为1,1,4,4,9,9,0。总和为28。

    由于答案可能很大,只需对1,000,000,007取模即可。

    Input
    第一行两个整数n(1<=n<=50000),p(1<=p<=30)。
    第二行4个数表示a0,0,a0,1,a1,0,a1,1。(这4个数都∈{0,1})
    第三行n个数bi(0<=bi<2^p)。
    Output
    一行表示答案。
    Input示例
    3 30
    0 1 1 0
    1 2 3
    Output示例
    28
    分析:挺好的一道题.
       先想想问题的简化版:不是求平方和,而是求和该怎么做. 肯定是不能枚举子集进行统计的. 二进制上的每一位都是独立的,如果是求最值,可以从高位到低位依次考虑,如果是求和,可以求出每一位是1的方案数,如果第i位为1,那么它对答案的贡献就是2^i * 第i位为1的方案数.
       另f[i][0/1]表示前i个数中,当前枚举的第j位为1的方案数.每个数都有选和不选两种选择. 最后的答案就是Σf[n][1] * 2^j
       如果是求平方和怎么办呢?(a1 + a2 + a3 +...... + an) ^ 2拆开来可以得到:a1 ^ 2 + a2 ^ 2 + a3 ^ 3 + ...... + an^2 + 2a1a2 + 2a1a3 + ...... + 2a1an + ...... + an-1an.每一项都与两位有关. 那么可以枚举两位j,k,求使得第j位和第k位都为1的方案数,它对答案的贡献就是2^(j+k) * 方案数,状态就要表示为f[i][0/1][0/1]了.
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    const ll mod = 1e9+7,maxn = 50010;
    ll n,p,a[2][2],b[maxn],f[maxn][2][2],ans;
    
    void Mod(ll &x)
    {
        if (x >= mod)
            x -= mod;
    }
    
    ll solve(ll x,ll y)
    {
        memset(f,0,sizeof(f));
        for (ll i = 1; i <= n; i++)
        {
            ll t1 = (b[i] >> x) & 1;
            ll t2 = (b[i] >> y) & 1;
            f[i][t1][t2]++;
            Mod(f[i][t1][t2]);
        }
        for (ll i = 1; i <= n; i++)
        {
            ll t1 = (b[i] >> x) & 1;
            ll t2 = (b[i] >> y) & 1;
            for (ll j = 0; j <= 1; j++)
                for (ll k = 0; k <= 1; k++)
                {
                    f[i][j][k] += f[i - 1][j][k];
                    Mod(f[i][j][k]);
                    f[i][a[j][t1]][a[k][t2]] += f[i - 1][j][k];
                    Mod(f[i][a[j][t1]][a[k][t2]]);
                }
        }
        return f[n][1][1];
    }
    
    int main()
    {
        scanf("%lld%lld",&n,&p);
        for (ll i = 0; i <= 1; i++)
            for (ll j = 0; j <= 1; j++)
                scanf("%lld",&a[i][j]);
        for (ll i = 1; i <= n; i++)
            scanf("%lld",&b[i]);
        for (ll i = 0; i < p; i++)
            for (ll j = 0; j < p; j++)
            {
                ll temp = (1LL << (i + j)) % mod * solve(i,j) % mod;
                ans += temp;
                Mod(ans);
            }
        printf("%lld
    ",ans);
    
        return 0;
    }
       
  • 相关阅读:
    ok
    Android设备激活量超10亿 3个月增长1亿台
    JavaWeb--文件的上传和下载
    JavaWeb--Listener
    JavaWeb--JSTL
    JavaWeb--自定义标签4--EL自定义函数
    JavaWeb--自定义标签4--带父标签的自定义标签
    codeforces 437B. The Child and Set 解题报告
    codeforces 437A. The Child and Homework 解题报告
    codeforces 435 B. Pasha Maximizes 解题报告
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8495759.html
Copyright © 2020-2023  润新知