zoukankan      html  css  js  c++  java
  • 【CF1463F】Max Correct Set

    题目

    题目链接:https://codeforces.com/contest/1463/problem/F
    规定一个正整数集合 (S)。当且仅当满足以下条件时该集合成立:

    • (S subseteq {1,2,...,n})
    • 如果 (a in s) 并且 (b in s),那么 (|a - b| ot ={x}) 并且 (|a - b| ot ={y})

    对于给定的数值 (n,x,y),你需要找到成立集合的最大大小。
    (nleq 10^9)(x,yleq 22)

    思路

    可以看作是一个长度为 (n)(01) 序列,要求任意的 (1) 的下标差不为 (x)(y)。最大化 (1) 的数量。
    首先对于一个长度为 (x+y)(01) 序列,如果它满足上述条件,那么把它重复若干次都一定满足条件。否则把每 (x+y) 个看作一块,对于两个不同块的 (1),如果它们下标为 (a,a+x),那么必然 (a+x-(x+y)=a-y) 也是 (1),而 (a)(a-y) 必然在同一块,所以这块并不合法。
    (x<y)(O((x+y)2^y)) 求出长度为 (x+y) 的块 (1) 最多出现次数。而答案就是这个块重复无限次的前 (n) 项。dp 的时候把贡献稍微改一下即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int M=(1<<22);
    int n,x,y,lim,ans,f[2][M];
    
    int main()
    {
    	scanf("%d%d%d",&n,&x,&y);
    	memset(f,0xcf,sizeof(f));
    	f[0][0]=0; lim=(1<<max(x,y))-1;
    	for (int i=0;i<x+y;i++)
    	{
    		int id=i&1,val=n/(x+y)+(i<n%(x+y));
    		memset(f[id^1],0xcf,sizeof(f[id^1]));
    		for (int s=0;s<=lim;s++)
    		{
    			int t=(s<<1)&lim;
    			f[id^1][t]=max(f[id^1][t],f[id][s]);
    			if (!(s&(1<<x-1)) && !(s&(1<<y-1)))
    				f[id^1][t|1]=max(f[id^1][t|1],f[id][s]+val);
    		}
    	}
    	int id=(x+y)&1;
    	for (int s=0;s<=lim;s++)
    		ans=max(ans,f[id][s]);
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    UVALive
    UVALive
    UVA
    UVALive
    BZOJ3597 SCOI2014方伯伯运椰子(分数规划+spfa)
    BZOJ3456 城市规划(多项式求逆)
    BZOJ4182 Shopping(点分治+树形dp)
    BZOJ4383 Pustynia(线段树+拓扑排序)
    BZOJ4445 SCOI2015小凸想跑步(半平面交)
    BZOJ5311 贞鱼(动态规划+wqs二分+决策单调性)
  • 原文地址:https://www.cnblogs.com/stoorz/p/15255720.html
Copyright © 2011-2022 走看看