题意:n(1e3),k(1e6),a1~ak(1e3)。选取最少的ai(可以重复)t个,使得sum(ai)/t/1000==n/1000成立。
题解:
k(1e6),a1~ak(1e3) --> 数只有1e3个。
sum(ai)/t/1000==n/1000 --> sum(ai)==t*n --> sum(ai-n)==0
t<=2000:在有解的情况下,最少存在一个解为:选取ai,aj,ai<n,aj>n,t=abs(ai)+abs(aj)
解法一:BFS
如果存在一组解b1+b2+...+bt==0,那么我们可以改变数组元素的位置使得所有前缀和范围在[-1000,1000]。
那么我们可以以0为起点进行BFS,直到又回到0。
解法二:dp+bitset
考虑朴素的dp写法,dp[i][j]表示选取了i个元素能否到达状态j。伪代码如下:
这样做的复杂度是n3,考虑到dp的状态只有01两种,我们可以用bitset优化。把第二层循环压成bitset,复杂度变成n3/64。
bitset内部实现:
内部维护了一个long数组,初始只有一个long,所以BitSet最小的size是64,当随着存储的元素越来越多,BitSet内部会动态扩充,最终内部是由N个long来存储,这些针对操作都是透明的。
k(1e6),a1~ak(1e3) --> 数只有1e3个。
sum(ai)/t/1000==n/1000 --> sum(ai)==t*n --> sum(ai-n)==0
t<=2000:在有解的情况下,最少存在一个解为:选取ai,aj,ai<n,aj>n,t=abs(ai)+abs(aj)
解法一:BFS
如果存在一组解b1+b2+...+bt==0,那么我们可以改变数组元素的位置使得所有前缀和范围在[-1000,1000]。
那么我们可以以0为起点进行BFS,直到又回到0。
解法二:dp+bitset
考虑朴素的dp写法,dp[i][j]表示选取了i个元素能否到达状态j。伪代码如下:
for(int i=1;i<=2000;++i) {//枚举次数,至多2000次
for(int j=0;j<=2000;++j) {//状态统一加1000变成正数
for(int x=1;x<=m;++x) {
if(0<=j-a[x]&&j-a[x]<=2000) d[i][j] |= d[i-1][j-a[x]];
}
}
}
这样做的复杂度是n3,考虑到dp的状态只有01两种,我们可以用bitset优化。把第二层循环压成bitset,复杂度变成n3/64。
bitset内部实现:
内部维护了一个long数组,初始只有一个long,所以BitSet最小的size是64,当随着存储的元素越来越多,BitSet内部会动态扩充,最终内部是由N个long来存储,这些针对操作都是透明的。
#include<cstdio>
#include<map>
#include<cstdlib>
#include<queue>
using namespace std;
#define mp make_pair
#define fi first
#define se second
const int N=2020;
map<int,bool> vis,vi;
int a[N];
int main() {
int x,m;
while(~scanf("%d%d",&x,&m)) {
///init
vis.clear();
vi.clear();
///read
int n=0;
for(int i=1;i<=m;++i) {
int t;scanf("%d",&t);
t-=x;
if(!vis[t]) a[++n]=t;
vis[t]=1;
}
///
if(x==0) {
if(vis[0]) puts("1");
else puts("-1");
continue;
}
///
int cnt0=0,cnt1=0;
for(int i=1;i<=n;++i) {
if(a[i]>0) ++cnt0;
if(a[i]<0) ++cnt1;
}
if(cnt0==n||cnt1==n) {
puts("-1");
continue;
}
///solve
queue<pair<int,int> > q;
q.push(mp(0,0));
bool flag=1;
int ans;
for(;flag;) {
pair<int,int> now=q.front();q.pop();
for(int i=1;i<=n;++i) {
if(now.fi+a[i]==0) {
flag=0;
ans=now.se+1;
break;
}
int nxt=now.fi+a[i];
if(abs(nxt)<=1000&&!vi[nxt]) {
q.push(mp(nxt,now.se+1));
vi[nxt]=1;
}
}
}
///print
printf("%d\n",ans);
}
return 0;
}
#include<cstdio>
#include<map>
#include<bitset>
using namespace std;
const int N=1007;
map<int,bool> vis;
bitset<N*2> dp[2];
int a[N];
int main() {
int x,m;
while(~scanf("%d%d",&x,&m)) {
///init
vis.clear();
///read
int n=0;
for(int i=1;i<=m;++i) {
int t;scanf("%d",&t);
if(!vis[t]) a[++n]=t;
vis[t]=1;
}
///solve
int now=0,ans=-1;
dp[now].reset();
dp[now][1000]=1;
for(int i=1;i<=2000&&ans==-1;++i) {
now=1-now;
dp[now].reset();
for(int j=1;j<=n;++j) {
dp[now] |= (dp[1-now]<<a[j])>>x;
if(dp[now][1000]) {
ans=i;
break;
}
}
}
///print
printf("%d\n",ans);
}
return 0;
}