• 题解 [HNOI2012]集合选数


    题目传送门

    题目大意

    直接看题面吧。

    思路

    感觉挺水的一道题啊?怎么评到紫色的啊?考试的时候LJS出了这个题的加强版我就只想出这个思路,然后就爆了。。。

    不难发现,我们可以构造矩阵:

    x 2x 4x 6x ... 
    3x 6x 12x 24x 48x ...
    9x 18x 36x ...
    

    然后实际上就相当于在这个矩阵中选出一些数使得两两不相邻。因为行数列数都是 (log) 级别的,所以直接状压就好了。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 1000000001
    #define MAXN 1000005
    
    template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
    template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
    template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> void Mx (T &a,T b){a = max (a,b);}
    template <typename T> void Mi (T &a,T b){a = min (a,b);}
    
    bool mark[MAXN];
    int n,a[25][25],lim[25];
    
    void init (int x){
    	a[1][1] = x;
    	for (Int i = 1;i <= 15;++ i){
    		if (i > 1) a[i][1] = a[i - 1][1] * 3;
    		if (a[i][1] > n) break;
    		for (Int j = 2;j <= 20;++ j){
    			a[i][j] = a[i][j - 1] * 2;
    			if (a[i][j] > n){
    				lim[i] = j - 1;
    				break;
    			}
    		}
    		for (Int j = 1;j <= lim[i];++ j) mark[a[i][j]] = 1;
    	}
    } 
    
    bool chk[1 << 21];
    int dp[2][1 << 22];
    
    int WorkDP (){
    	int endl = 0;
    	for (Int i = 0;i < (1 << lim[1]);++ i) dp[1][i] = chk[i];
    	for (Int i = 2;i <= 15;++ i){
    		if (a[i][1] > n){
    			endl = i - 1;
    			break;
    		}
    		for (Int S = 0;S < (1 << lim[i]);++ S) if (chk[S]){
    			dp[i & 1][S] = 0;
    			for (Int S1 = 0;S1 < (1 << lim[i - 1]);++ S1)
    				if ((S & S1) == 0) dp[i & 1][S] += dp[i - 1 & 1][S1],dp[i & 1][S] %= mod;
    		}
    		else dp[i & 1][S] = 0;
    	}
    	int ans = 0;
    	for (Int S = 0;S < (1 << lim[endl]);++ S) ans += dp[endl & 1][S],ans %= mod;
    	return ans;
    }
    
    signed main(){
    	read (n);int res = 1;
    	for (Int i = 0;i < (1 << 20);++ i) chk[i] = ((i & (i >> 1)) == 0);
    	for (Int i = 1;i <= n;++ i) if (!mark[i]) init (i),res = 1ll * res * WorkDP () % mod;
    	write (res),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    UVa 439,Knight Moves
    UVa127,"Accordian" Patience
    UVa11882,Biggest Number
    UVa1599,Ideal Path
    我什么时候才能脱离题解....
    UVa208,Firetruck
    UVa1600,Patrol Robot
    UVa12325, Zombie's Treasure Chest
    随笔
    UVa11054
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13858307.html
Copyright © 2020-2023  润新知