1. 程式人生 > >loj2030 「SDOI2016」儲能表

loj2030 「SDOI2016」儲能表

cin RR details scanf stream lld htm n) 數值

ref
ref

一個點就是一個數對 \((x,y)\)

記狀態 \(f[i][1/0][1/0][1/0]\)\(g[i][1/0][1/0][1/0]\),其中三個 \(1/0\) 取值分別代表“\(x\) 在前 \(i\) 位卡滿 \(n\)(的前 \(i\) 位)/小於它”、“\(y\) 在前 \(i\) 位卡滿 \(m\)(的前 \(i\) 位)/小於它”、“\(k_{current}\) 在前 \(i\) 位卡滿 \(k\)(的前 \(i\) 位)/大於它”。\(f\) 是數值和,\(g\) 是方案數。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std; typedef long long ll; int T, f[62][2][2][2], g[62][2][2][2]; ll n, m, k, p; int main(){ cin>>T; while(T--){ scanf("%lld %lld %lld %lld", &n, &m, &k, &p); memset(f, 0, sizeof(f)); memset(g, 0, sizeof(g)); g[61][1][1][1] = 1
; for(int i=60; i>=0; i--){ int dn=(n>>i)&1, dm=(m>>i)&1, dk=(k>>i)&1; //取出 $n,m,k$ 的第 $i$ 位 for(int a=0; a<=1; a++) for(int b=0; b<=1; b++) for(int c=0; c<=1; c++) if
(f[i+1][a][b][c] || g[i+1][a][b][c]) for(int ia=0; ia<=1; ia++) for(int ib=0; ib<=1; ib++){ int ic=ia^ib; //確定當前第 $i$ 位上的 $x,y,k_{current}$ 的數值 if(a && ia>dn) continue; //明明前頭卡滿了,現在又大了,就不合法了 if(b && ib>dm) continue; if(c && ic<dk) continue; int in=a&&ia==dn; //是否現在還卡滿 int im=b&&ib==dm; int ik=c&&ic==dk; g[i][in][im][ik] = (g[i][in][im][ik] + g[i+1][a][b][c]) % p; f[i][in][im][ik] = (f[i][in][im][ik] + (f[i+1][a][b][c] + (ll)(ic-dk+p) % p * ((1ll<<i) % p) % p * g[i+1][a][b][c] % p) % p) % p; } } printf("%d\n", f[0][0][0][0]); } return 0; }

loj2030 「SDOI2016」儲能表