4513: [Sdoi2016]储能表

4513: [Sdoi2016]储能表

链接

分析:

  数位dp。

  横坐标和纵坐标一起数位dp,分别记录当前横纵坐标中这一位是否受n或m的限制,在记录一维表示当前是否已经大于k了。

  然后需要两个数组记录答案,分别记录个数和答案的和。

  语意不清了。。。看代码吧。。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define fi(s) freopen(s,"r",stdin);
#define fo(s) freopen(s,"w",stdout);
using namespace std;
typedef long long LL;

inline LL read() {
    LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 1005;
int a[N], b[N], c[N], c1, c2, c3, Cnt;
LL dp[N][2][2][2], mi[N], cnt[N][2][2][2], n, m, k, p;
#define pa pair<LL,LL>

pa dfs(int x,LL now,bool l1,bool l2,bool l3) {
    if (!x) { return pa((-k + p) % p, 1); }
    if (dp[x][l3][l1][l2]) return pa(dp[x][l3][l1][l2], cnt[x][l3][l1][l2]);
    int u1 = l1 ? a[x] : 1;
    int u2 = l2 ? b[x] : 1;
    LL res = 0, sum = 0;
    for (int i = 0; i <= u1; ++i) 
        for (int j = 0; j <= u2; ++j) {
            int t = i ^ j;
            if (l3 && t < c[x]) continue;
            pa tmp = dfs(x - 1, t ? now + mi[x - 1] : now, l1 && i == u1, l2 && j == u2, l3 && t == c[x]);
            res += (tmp.first + tmp.second * t * mi[x - 1] % p) % p;
            sum += tmp.second;
            res %= p;
            sum %= p;
        }
    dp[x][l3][l1][l2]= res, cnt[x][l3][l1][l2] = sum;
    return pa(res, sum);
}
void Calc() {
    n --, m --;
    c1 = c2 = c3 = Cnt = 0;
    LL t = n; 
    while (t) a[++c1] = t % 2, t /= 2;
    t = m; 
    while (t) b[++c2] = t % 2, t /= 2;
    t = k;
    while (t) c[++c3] = t % 2, t /= 2;
    Cnt = max(c1, max(c2, c3));
    cout << dfs(Cnt, 0, 1, 1, 1).first << "\n";
    for (int i = 0; i <= Cnt; ++i) a[i] = b[i] = c[i] = 0;
    memset(dp, 0, sizeof(dp));
    memset(cnt, 0, sizeof(cnt));
}
void solve() {
    n = read(), m = read(), k = read(), p = read();
    mi[0] = 1;
    for (int i = 1; i <= 100; ++i) mi[i] = mi[i - 1] * 2 % p;
    Calc();
}
int main() {
    for (int T = read(); T --; solve());    
    return 0;
}

 

posted @ 2019-02-17 19:28  MJT12044  阅读(236)  评论(0编辑  收藏  举报