题目大意
题目很好理解,有n个小朋友,m种糖果,每个小朋友分别有 Ai dollars,每种糖果单价分别为 Bj dollars,每个小朋友会有一种喜爱的糖果,小朋友只会购买自己喜欢的糖果直到自己的钱不够买为止。现有q个询问,问有几个小朋友会剩 k dollars?
分析
题目思想为求 A%B=k 的种数,转化一下变成求(A-k)%B=0 的种数,即(A-k)是 B 的倍数的种数,那么我们就来枚举B,然后利用bitset分别标记B的倍数。
由于只有糖果的单价大于剩下的钱,小朋友才可能会有剩下的钱。所以在枚举过程中我们从大到小枚举 B,这样就保证在计算剩余 k 的时候所有需要的B均已被标记,但是不能先于 k 将所有 B 的倍数均标记。
这里介绍一下本题中用到的bitset的内容:bitset是C++语言的一个类库,用来处理一系列bit位。
用bitset存储整型数时,eg:
bieset<5>a; a.set(2); a.set(3);
a 中存储的是01100 ,即用0和1标记。
a.flip(i);
将 第 i 位取反
a.reset();
将a全部置零
a.count();
返回a中1的个数
关键代码
ans[i]=(buff&(a>>i)).count()&1;
buff 存储当前标记的 B 的倍数, a>>i 等同于 A-k
if(b[i]) for(int j=0;j<=maxa;j+=i) buff.flip(j);
标记B的倍数
下面给出代码
#include<iostream>
#include<stdio.h>
#include<bitset>
using namespace std;
#define N 50005
bitset<N> a,b,buff,ans;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m,q,num;
int maxa=0;
int maxb=0;
scanf("%d%d%d",&n,&m,&q);
a.reset();
b.reset();
buff.reset();
ans.reset();
for(int i=1;i<=n;i++)
scanf("%d",&num),a.set(num),maxa=max(maxa,num);
for(int j=1;j<=m;j++)
scanf("%d",&num),b.set(num),maxb=max(maxb,num);
for(int i=maxb;i>=0;i--)
{
ans[i]=(buff&(a>>i)).count()&1;
if(b[i])
for(int j=0;j<=maxa;j+=i)
buff.flip(j);
}
for(int i=1;i<=q;i++)
scanf("%d",&num),printf("%d\n",ans[num]?1:0);
}
return 0;
}