zoukankan      html  css  js  c++  java
  • BZOJ4513 SDOI2016储能表(数位dp)

      如果n、m、k都是2的幂次方,答案非常好统计。于是容易想到数位dp,考虑每一位是否卡限制即可,即设f[i][0/1][0/1][0/1]为第i位是/否卡n、m、k的限制时,之前的位的总贡献;g[i][0/1][0/1][0/1]为第i位是/否卡n、m、k的限制时,之前的位的方案数。为了方便可以改为统计小于k的贡献再减去。

      莫名其妙的搞错了很多地方,简直调一年,不知道在干啥。

      人丑常数大,根本没办法。

      (突然发现以前大部分数位dp都是直接按位计数就搞出来了……这个题应该也行。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 64
    ll read()
    {
        ll x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int T,p,f[N][2][2][2],g[N][2][2][2],a[N],b[N],c[N],q[N];
    ll n,m,k;
    void inc(int &x,int y,int p){x+=y;if (x>=p) x-=p;}
    void calc(ll n,ll m,ll k,int p)
    {
        memset(f,0,sizeof(f));memset(g,0,sizeof(g));
        int t=-1;ll x=max(max(n,m),k);
        while (x) t++,x>>=1;
        for (int i=0;i<=t;i++) a[i]=(n&(1ll<<i))>0;
        for (int i=0;i<=t;i++) b[i]=(m&(1ll<<i))>0;
        for (int i=0;i<=t;i++) c[i]=(k&(1ll<<i))>0;
        g[t+1][1][1][1]=1;
        for (register int i=t;~i;i--)
            for (register int x=0;x<=1;x++)
                for (register int y=0;y<=1;y++)
                    for (register int z=0;z<=1;z++)
                        for (register int u=x;u<=1;u++)
                            for (register int v=y;v<=1;v++)
                                for (register int w=z;w<=1;w++)
                                {
                                    int t=(!w|c[i]&z)?(((!u|a[i]&x)&(!v|b[i]^y))+((!v|b[i]&y)&(!u|a[i]^x))):0;
                                    inc(f[i][x][y][z],1ll*q[i]*g[i+1][u][v][w]%p*t%p,p);
                                    if (!w|c[i]^z) t+=(((!u|a[i]&x)&(!v|b[i]&y))+((!u|a[i]^x)&(!v|b[i]^y)));
                                    inc(f[i][x][y][z],1ll*f[i+1][u][v][w]*t%p,p);
                                    inc(g[i][x][y][z],1ll*g[i+1][u][v][w]*t%p,p);
                                }
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4513.in","r",stdin);
        freopen("bzoj4513.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        T=read();
        while (T--)
        {
            n=read()-1,m=read()-1,k=read(),p=read();
            q[0]=1;for (int i=1;i<=63;i++) q[i]=(q[i-1]<<1)%p;
            int ans=0;
            calc(n,m,max(n,m)<<1,p);
            for (int x=0;x<=1;x++)
                for (int y=0;y<=1;y++)
                    for (int z=0;z<=1;z++)
                    inc(ans,f[0][x][y][z],p),inc(ans,p-1ll*k%p*g[0][x][y][z]%p,p);
            calc(n,m,k,p);
            for (int x=0;x<=1;x++)
                for (int y=0;y<=1;y++)
                    for (int z=0;z<=1;z++)
                    inc(ans,p-f[0][x][y][z],p),inc(ans,1ll*k%p*g[0][x][y][z]%p,p);
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    2019.6.1 模拟赛——[ 费用流 ][ 数位DP ][ 计算几何 ]
    LOJ 2721 「NOI2018」屠龙勇士——扩展中国剩余定理
    AGC033 D~F——[ 值放到角标的DP ][ 思路+DP ][ 思路 ]
    LOJ 2719 「NOI2018」冒泡排序——模型转化
    LOJ 3094 「BJOI2019」删数——角标偏移的线段树
    CF 717A Festival Organization——斯特林数+递推求通项+扩域
    LOJ 3090 「BJOI2019」勘破神机——斯特林数+递推式求通项+扩域
    洛谷 4723 【模板】线性递推——常系数线性齐次递推
    bzoj 3924 幻想乡战略游戏 —— 动态点分治
    计算几何整理
  • 原文地址:https://www.cnblogs.com/Gloid/p/9883764.html
Copyright © 2011-2022 走看看