zoukankan      html  css  js  c++  java
  • ICPC2020 济南站 L 题 (数位dp)

    题目链接:

    发现 (m) 很小,所以只需要先数位 (dp),然后暴力枚举后 (8) 位的情况即可,因为涉及到进位,所以还需要维护第八位之前有几个连续的 (1)
    (dp[0/1][i][0/1][0/1]) 表示,当前到第 (i) 位,卡不卡上界,从第 (i) 位向前有多少个连续的 (1)(奇偶), 有多少个 (1) (奇偶)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 110;
    
    int T, m, lev; ll L;
    int a[maxn], c[maxn], d[maxn], cnt = 0;
    int su[600]; 
    ll A1[2][65],A2[2][65];
    
    ll dp[2][65][2][2];
    
    ll dfs(int pos, int sum, int in, int lim){
    	if(dp[lim][pos][sum & 1][in & 1] != -1) return dp[lim][pos][sum & 1][in & 1];
    	if(pos >= cnt + 1 - 8){
    		ll res = 0;
    		if(lim) res += A1[sum & 1][in & 1];
    		else res += A2[sum & 1][in & 1];
    		dp[lim][pos][sum & 1][in & 1] = res;
    		return res;
    	}
    
    	ll res = 0;
    	int li = (lim) ? (c[pos]) : 1;
    	for(int i = 0 ; i <= li ; ++i){
    		if(i == 0) res += dfs(pos + 1, sum + i, 0, lim & (i == li));
    		else res += dfs(pos + 1, sum + i, in + i, lim & (i == li));
    	}
    	dp[lim][pos][sum & 1][in & 1] = res;
    	return res; 
    }
    
    ll calc(ll x){
    	cnt = 0;
    	ll tmp = x;
    	while(tmp){
    		c[++cnt] = tmp % 2ll;
    		tmp /= 2ll;
    	}
    	
    	for(int i = 1 ; i <= cnt / 2 ; ++i) swap(c[i], c[cnt - i + 1]);
    		for(int sum=0;sum<=1;++sum){
    			for(int in = 0;in <= 1;++in ){
    				for(int i = 0 ; i <= lev ; ++i){
    					int tmp=1;
    					for(int j = 0 ; j < m ; ++j){			
    						if(i+j>=256){
    							tmp &= (((sum + su[i+j] - in)%2+2)%2== a[j]);
    						}else{
    							tmp &= (((sum + su[i+j]) % 2+2)%2 == a[j]);
    						}
    					}
    					A1[sum][in]+=tmp; 
    				}
    				for(int i = 0 ; i < 256 ; ++i){
    					int tmp=1;
    					for(int j = 0 ; j < m ; ++j){			
    						if(i+j>=256){
    							tmp &= (((sum + su[i+j] - in)%2+2)%2== a[j]);
    						}else{
    							tmp &= (((sum + su[i+j]) % 2+2)%2 == a[j]);
    						}
    					}
    					A2[sum][in]+=tmp; 
    				}
    			}
    		}
    	return dfs(1, 0, 0, 1);
    }
    
    int main(){
    	scanf("%d", &T);
    	for(int i = 0 ; i < 512 ; ++i){
    		int tmp = i;
    		while(tmp){
    			su[i] += (tmp & 1);
    			tmp >>= 1;
    		}
    	}
    	while(T--){
    		memset(dp, -1, sizeof(dp));
    		memset(A1,0,sizeof(A1)); 
    		memset(A2,0,sizeof(A2));
    		scanf("%d%lld", &m, &L);
    		lev = L % (1 << 8);
    		for(int i = 0 ; i < m ; ++i) scanf("%d", &a[i]);
    		
    		printf("%lld
    ", calc(L));
    	}
    	return 0;
    }
    
  • 相关阅读:
    20169205 2016-2017-2 《移动平台应用开发实践》第4周学习总结
    20169205 2016-2017-2《网络攻防》第4周总结
    20169205 2016-2017-2 《移动平台应用开发实践》第3周学习总结
    tcpdump使用
    wireshark使用
    20169205 2016-2017-2《网络攻防》第3周总结
    OpenSSH/PuTTY/SSH使用
    Aircrack使用
    Metasploit使用
    20155325 2017-2018 1 《信息安全系统设计基础》 第十周学习总结
  • 原文地址:https://www.cnblogs.com/tuchen/p/14204100.html
Copyright © 2011-2022 走看看