zoukankan      html  css  js  c++  java
  • BZOJ 4513 储能表

    数位DP?我哪会

    [0,n-1]可以拆成log段一定前缀之后任意的区间

    (log^2) 枚举区间对计数即可

    #include <cstdio>
    #include <algorithm>
    
    using std::min;
    using std::max;
    
    int T;
    
    long long N, M, K;
    long long n, m, kl, kr;
    
    int Cnt, Sum;
    
    int MOD;
    
    int sr;
    int sum(int a, int b){
    	sr=a+b;
    	if(sr>=MOD)	sr-=MOD;
    	return sr;
    }
    
    int mul(int a, int b){
    	return (int)((1LL*a*b)%(long long)(MOD));
    }
    
    int Norm(long long n){
    	return (int)(n%(long long)(MOD));
    }
    
    int Calc(long long n){
    	if(n&1LL)
    		return mul(Norm(n), Norm((n+1LL)>>1));
    	else	return mul(Norm(n>>1), Norm(n+1LL));
    }
    
    void Update(long long l, long long r, long long k){
    	Cnt=sum(Cnt, mul(Norm(r-l), Norm(k)));
    	Sum=sum(Sum, mul(sum(Calc(r), MOD-Calc(l)), Norm(k)));
    }
    
    int main(){
    	
    	scanf("%d", &T);
    	
    	while(T--){
    		
    		scanf("%lld%lld%lld%d", &N, &M, &K, &MOD);
    		
    		Sum=0;Cnt=0;
    		
    		for(int i=0;i<60;++i){
    			if((N>>i)&1){
    				n=(N>>(i+1))<<(i+1);
    				for(int j=0, l;j<60;++j){
    					if((M>>j)&1){
    						m=(M>>(j+1))<<(j+1);
    						l=max(i, j);
    						kl=n^m;kl=(kl>>l)<<l;
    						kr=kl+(1LL<<l)-1LL;
    						if(K<kr)	Update(max(kl-1, K), kr, (1LL<<min(i, j)));
    					}
    				}
    			}
    		}
    		
    		Sum=sum(Sum, MOD-mul(Cnt, Norm(K)));
    		
    		printf("%d
    ", Sum);
    		
    	}
    	
    	
    	
    	
    	return 0;
    }
    
    /*
    3
    2 2 0 100
    3 3 0 100
    3 3 1 100
    
    2
    12
    6
    
    */
    
    
  • 相关阅读:
    C 字符串
    C 函数指针、回调函数
    C 指针
    C 数组、枚举类型enum
    C 函数声明、函数参数
    C 内置函数
    C 流程控制
    C 储存类与运算符
    C变量和常量
    名词解释
  • 原文地址:https://www.cnblogs.com/Pickupwin/p/BZOJ4513.html
Copyright © 2011-2022 走看看