卧薪尝胆,厚积薄发。
一排数
Date: Wed Jan 02 21:05:18 CST 2019 In Category: NoCategory

Description:

给 $n$ 个正整数 $c_i$ ,求重排后依次取模答案的最大值。
$1\leqslant n\leqslant 10^5$

Solution:

首先将 $c$ 排序,若 $c_1$ 只出现一次答案就是 $c_1$ ,否 则答案一定小于 $c_1$ 。
发现实际有用的一定是依次递减的,也就是说问题可以变成选 $k$ 个数,降序排序然后依次模过去。
那么我们可以先把所有数降序排序,然后暴力 $dp$ , $f[i]$ 表示数字 $i$ 是否可以达到,转移为: $$ f[i]=\bigcup_{i=1}^{n-1}\bigcup_{k}f[i+kv[i]] $$ 那么我们可以用一个 $g$ 来维护所有 $kv$ ,每次从大往小枚举判断是否可以被模出,如果这个数字已经存在,那么 $f[i]=true$ ,同时暴力在 $g$ 中标记他的所有倍数,这个是 $O(n\ln n)$ 的,如果这个数字不存在,就看 $f>>i\&g$ 是否有值,用 $bitset$ 可以优化到 $\frac {n^2}w$ 。

Code:


#include<bits/stdc++.h>
using namespace std;
int n;
#define MAXN 100010
int a[MAXN];
bitset<MAXN> f,g;
bool vis[MAXN];
int main()
{
freopen("array.in","r",stdin);
freopen("array.out","w",stdout);
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])
{
cout << a[1] << endl;
return 0;
}
n = unique(a + 1,a + 1 + n) - a - 1;
for(int i = 1,j = n;i < j;++i,--j)swap(a[i],a[j]);
int mx = 0;
for(int i = 1;i <= n;++i)
{
vis[a[i]] = true;
mx = max(mx,a[i]);
}
f[0] = 1;
for(int i = mx;i >= 1;--i)
{
if(vis[i])
{
for(int j = i;j <= mx;j += i)g[j] = 1;
f[i] = 1;
}
else f[i] = ((f >> i) & g).any();
}
int ans;
for(int i = a[n] - 1;i >= 0;--i)if(f[i]){ans = i;break;}
cout << ans << endl;
return 0;
}
In tag: STL-bitset
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡