zoukankan      html  css  js  c++  java
  • JZOJ 4314. 【NOIP2015模拟11.4】老司机

    题目

    思路

    大意是构造一个数组使它做 (01) 背包能表示出所有给定的数
    那就暴力枚举每个位置填什么
    直到它能表示出所有给定的数
    为了保证时间复杂度
    我们考虑一个二进制数 (s) 表示能构造出的数
    (s) 的第 (i) 位为一就表示当前枚举出的数组能表示出 (i) 这个数
    那么假如一个数就是 (s|(s << i)|(1<<i))
    表示每位加上 (i) 的数是可以被表示的
    小优化:当前填到这位可以构造出给定的所有数时,给当前位打个标记
    以后做到这一位就可以直接 (return)
    对应下面的 (b) 数组

    (Code)

    #include<cstdio>
    using namespace std;
    typedef long long LL;
    
    const int N = 25;
    int n;
    LL a[N] , b[N] , c[N] , anss[N] , ans = 0x3f3f3f3f;
    
    inline void dfs(int x , LL s)
    {
    	if (b[x - 1] || x - 1 >= ans) return;
    	int fl = 0;
    	for(register int i = 1; i <= n; i++)
    	if (!(s & (1LL << a[i])))
    	{
    		fl = 1;
    		break;
    	}
    	if (!fl)
    	{
    		ans = x - 1 , b[x - 1] = 1;
    		for(register int i = 1; i < x; i++) anss[i] = c[i];
    		return;
    	}
    	if (x > 6) return;
    	for(register int i = c[x - 1]; i <= 50; i++)
    	{
    		c[x] = i;
    		dfs(x + 1 , (s | (s << i)) | (1LL << i));
    		if (b[x]) return;
    	}
    }
    
    int main()
    {
    	freopen("driver.in" , "r" , stdin);
    	freopen("driver.out" , "w" , stdout);
    	scanf("%d" , &n);
    	for(register int i = 1; i <= n; i++) scanf("%lld" , a + i);
    	c[0] = 1;
    	dfs(1 , 0);
    	printf("%lld
    " , ans);
    	for(register int i = 1; i <= ans; i++) printf("%lld " , anss[i]);
    }
    
  • 相关阅读:
    OC中ARC forbids explicit message send of release错误
    OC中内存管理(转)
    [题解]数学期望_luogu_P1850_换教室
    [题解](单调队列)luogu_P2216_BZOJ_1047 理想的正方形
    [题解]luogu_AT1224_JOIOJI
    [题解]区间dp_luogu_P3147 262144
    [筆記]歐拉路
    [題解/狀壓dp]POJ_2411_Mondriaan's dream
    [題解]luogu_P1854 花店櫥窗佈置
    [題解]luogu_P1052 過河
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/13429795.html
Copyright © 2011-2022 走看看