• HDU 5657 CA Loves Math 状压DP + 枚举


    题意:

    给出(A(2 leq A leq 11), n(0 leq n leq 10^9), k(1 leq k leq 10^9))
    求区间([1, A^n])中各个数字互不相同的(A)进制数而且是(k)的倍数的个数。

    分析:

    如果(n > A),根据抽屉原理,(n)(A)进制数一定会有重复的数字。
    所以下面只讨论(n leq a)的情况。

    对于(k)的大小,分别使用不同的算法:

    • (k)比较小的时候,用状压DP:(d(S, x))表示当前数字集合为(S)且模(k)(x)的数字的个数。
      在数字的末位添加一个未在集合(S)出现的数字(i),则转移到状态(d(S',(x cdot A + i) % k))

    • (k)比较大的时候,直接暴力统计。枚举区间内所有(k)的倍数,判断一下如果没有重复数字答案+1。

    第一种算法的复杂度为(O(2^A cdot k cdot A)),状态数乘转移数。
    第二种算法复杂度为(O(A^n/k cdot A)),枚举次数乘判断时间。

    找到一个合适的边界使得时限都能承受两种算法,测试了一下(25000)(30000),运行时间都是(3s)多,可以AC。

    PS:(n=0)(n=1)这些边界情况最好特判一下。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    
    int A, n, k;
    const int maxk = 30000;
    const int maxa = 11;
    
    LL d[1 << maxa][maxk];
    
    int bitcount(int x) {
    	int ans = 0;
    	while(x) { if(x & 1) ans++; x >>= 1; }
    	return ans;
    }
    
    bool check(LL x) {
    	int S = 0;
    	while(x) {
    		int t = x % A;
    		x /= A;
    		if(S & (1 << t)) return false;
    		S |= (1 << t);
    	}
    	return true;
    }
    
    int main()
    {
    	int T; scanf("%d", &T);
    	while(T--) {
    		scanf("%d%d%d", &A, &n, &k);
    
    		if(n == 0) {
    			if(k == 1) printf("1
    ");
    			else printf("0
    ");
    			continue;
    		}
    		if(n == 1) {
    			printf("%d
    ", A / k);
    			continue;
    		}
    
    		//DP
    		if(k < maxk) {
    			memset(d, 0, sizeof(d));
    			for(int i = 1; i < A; i++) d[1 << i][i % k] = 1;
    			for(int S = 0; S < (1 << A); S++) if(bitcount(S) < n) {
    				for(int x = 0; x < k; x++) if(d[S][x]) {
    					for(int i = 0; i < A; i++) if(!(S&(1<<i))) {
    						d[S|(1<<i)][(x*A+i)%k] += d[S][x];
    					}
    				}
    			}
    			LL ans = 0;
    			for(int S = 0; S < (1 << A); S++)
    				if(d[S][0]) ans += d[S][0];
    			printf("%lld
    ", ans);
    		} else {
    	    	if(n > A) n = A;
    	    	LL An = 1; //A^n
        		for(int i = 1; i <= n; i++) An *= A;
    			LL ans = 0;
    			for(LL t = k; t <= An; t += k)
    				if(check(t)) ans++;
    			printf("%lld
    ", ans);
    		}
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    桟错误分析方法
    gstreamer调试命令
    sqlite的事务和锁,很透彻的讲解 【转】
    严重: Exception starting filter struts2 java.lang.NullPointerException (转载)
    eclipse 快捷键
    POJ 1099 Square Ice
    HDU 1013 Digital Roots
    HDU 1087 Super Jumping! Jumping! Jumping!(动态规划)
    HDU 1159 Common Subsequence
    HDU 1069 Monkey and Banana(动态规划)
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/5357413.html
Copyright © 2020-2023  润新知