把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P4067 [SDOI2016]储能表

题面传送门
dp?直接算贡献!
我们首先来考虑如果\(n=2^{N},m=2^{M},N\leq M\)怎么做。
则显然,\(i\operatorname{xor}j\)会在每个\(k\in [0,m-1]\) 之间都取到\(n\)次。
那对于一般的\(nm\)怎么做呢?
直接拆成\(\log n\times \log m\)个段分开算就好了。
时间复杂度\(O(T\log n\log m)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (512+5)
#define M (100000+5)
#define K (6)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int T,p,x,y;ll n,m,k,Ans,Ns,Ms;
I ll calc(ll x,ll y){if((x+y)%2==0) return (x+y)/2%p*((y-x+1)%p)%p;else return (y-x+1)/2%p*((x+y)%p)%p;}
I void Solve(){
	int i,j;Ans=0;scanf("%lld%lld%lld%d",&n,&m,&k,&p);for(i=0;(1ll<<i)<=n;i++){
		if(!(n>>i&1)) continue;for(j=0;(1ll<<j)<=m;j++) {if(!(m>>j&1)) continue;Ns=n^(1ll<<i);Ms=m^(1ll<<j);
			x=min(i,j);y=max(i,j);Ans+=(1ll<<x)%p*calc(max((((Ms>>y)<<y)^(Ns>>y)<<y)-k,0),max((((Ms>>y)<<y)^(Ns>>y)<<y)-k+(1ll<<y)-1,0))%p;//cerr<<x<<' '<<y<<' '<<Ans<<'\n';
		}
	}printf("%lld\n",Ans%p);
}
int main(){
	freopen("1.in","r",stdin);
	scanf("%d",&T);while(T--) Solve();
} 
posted @ 2022-06-28 13:37  275307894a  阅读(47)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end