雅礼集训 Day10 T1 数字重排 【bitset优化DP】
题目分析:
容易发现将Ci从小到大排序后,若,直接输出即可
若,那么答案一定小于
容易发现当一个数模了一个较小的数后,再模一个大数就没有意义了
于是在这个基础上想到DP,设表示i能否在模的过程中被取到,最后的合法答案就是到中最大的为1的数,显然应该由大到小转移,于是枚举从到1
- 若,那么,同时给i的倍数打上标记
- 若是由某个数模后得到的,就需要存在一个使得且是前面某个的倍数(被标记过)
暴力转移的时间复杂度是,105的范围无法承受
我们把标记数组记为,那么第二种情况的条件就是存在,这样的条件约束是典型的bitset优化(典型到我闻所未闻。。。),等价于,any表示存在某一位为1
听说bitset常用于跑105的算法。。。
所以算法的时间复杂度就是
代码巨短:
#include<cstdio>
#include<bitset>
#include<algorithm>
#define maxn 100005
using namespace std;
int n,a[maxn];
bitset<maxn>f,g;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
if(a[1]!=a[2]) printf("%d",a[1]),exit(0);
n=unique(a+1,a+1+n)-a-1;
f[0]=1;
for(int i=a[n],j=n;i>=1;i--)
if(a[j]==i){
f[i]=1;
for(int k=j;k<=a[n];k+=j) g[k]=1;
j--;
}
else if(((f>>i)&g).any()) f[i]=1;
for(int i=a[1]-1;i>=0;i--) if(f[i]) printf("%d",i),exit(0);
}
PS:也可以让C由大到小排序,令表示前i个数能否得到j,转移就先继承前面的,再枚举k,,复杂度。。。似乎有点炸
贴一个bitset常用函数