zoukankan      html  css  js  c++  java
  • dtoi2677「SDOI2016」储能表

    题意:

         有一个 $ n $ 行 $ m $ 列的表格,行从 $ 0 $ 到 $ n - 1 $ 编号,列从 $ 0 $ 到 $ m - 1 $ 编号。

         每个格子都储存着能量。最初,第 $ i $ 行第 $ j $ 列的格子储存着 $ (i mathbin{ ext{xor}} j) $ 点能量。所以,整个表格储存的总能量是

    $$ sumlimits_{i = 0} ^ {n - 1} sumlimits_{j = 0} ^ {m - 1} (i mathbin{ ext{xor}} j) $$

         随着时间的推移,格子中的能量会渐渐减少。一个时间单位,每个格子中的能量都会减少 $ 1 $。显然,一个格子的能量减少到 $ 0 $ 之后就不会再减少了。

         也就是说,$ k $ 个时间单位后,整个表格储存的总能量是

    $$ sumlimits_{i = 0} ^ {n - 1} sumlimits_{j = 0} ^ {m - 1} max((i mathbin{ ext{xor}} j) - k, 0) $$

         给出一个表格,求 $ k $ 个时间单位后它储存的总能量。

         由于总能量可能较大,输出时对 $ p $ 取模,多组数据。

         $ T = 5000 $,$ n leq 10 ^ {18} $,$ m leq 10 ^ {18} $,$ k leq 10 ^ {18} $,$ p leq 10 ^ 9 $

    题解:

         先将问题稍加转化,只需要求有多少个 $(i,j)$ 满足异或值大于 $k$,以及这些位置的异或值之和即可。

         然后发现数据范围非常大,考虑数位dp。$f[i][0/1][0/1][0/1]和g[i][0/1][0/1][0/1]$分别表示前 $i$ 位,行坐标小于还是等于 $n$,列坐标小于还是等于 $m$,当前的异或的值等于还是大于 $k$ 的总和以及方案数。分别枚举两个数字的下一位是 $0$ 还是 $1$ 即可转移。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    int T,p,f[62][2][2][2],g[62][2][2][2];
    long long n,m,K;
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%lld%lld%lld%d",&n,&m,&K,&p);
            memset(f,0,sizeof(f));memset(g,0,sizeof(g));
            f[61][1][1][0]=0;g[61][1][1][0]=1;
            for (int i=61;i>=1;i--)
            for (int j=0;j<=1;j++)
            for (int k=0;k<=1;k++)
            for (int l=0;l<=1;l++)
            for (int a=0;a<=1;a++)
            for (int b=0;b<=1;b++)
            {
                int c,d,e;
                if ((1ll<<i-1)&n)
                {
                    if (!a)c=0;else c=j;
                }
                else
                {
                    if (j && a)continue;else c=j;
                }
                if ((1ll<<i-1)&m)
                {
                    if (!b)d=0;else d=k;
                }
                else
                {
                    if (k && b)continue;else d=k;
                }
                if ((1ll<<i-1)&K)
                {
                    if (!l && !(a^b))continue;else e=l;
                }
                else
                {
                    if (a^b)e=1;else e=l;
                }
                f[i-1][c][d][e]=((long long)f[i-1][c][d][e]+f[i][j][k][l]+g[i][j][k][l]*(a^b)*((1ll<<i-1)%p))%p;
                g[i-1][c][d][e]=(g[i-1][c][d][e]+g[i][j][k][l])%p;
            }
            printf("%lld
    ",((f[0][0][0][1]-(long long)g[0][0][0][1]*(K%p)%p)%p+p)%p);
        }
        return 0;
    }
  • 相关阅读:
    华为数据之道03
    机器学习10讲 第二讲
    机器学习10讲 第一讲
    07.TensorFlow双向循环神经网络
    06.TensorFlow循环神经网络
    华为数据之道:华为数据治理2
    线性回归
    MySQL配置文件my.cnf的理解
    Linux怎么查看软件安装路径 查看mysql安装在哪
    hadoop-2.7.4-nodemanager无法启动问题解决方案
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/14406928.html
Copyright © 2011-2022 走看看