该式子可以转化为:
不妨转化为
当右边为一个定值的时候,即为讨论方程解的存在性问题
根据 n个整数间的裴蜀定理:
设a1,a2,a3......an为n个整数,d是它们的最大公约数,那么存在整数x1......xn使得x1*a1+x2*a2+...xn*an=d。
特别来说,如果a1...an存在任意两个数是互质的(不必满足两两互质),那么存在整数x1......xn使得x1*a1+x2*a2+...xn*an=1。证法类似两个数的情况。
我们得出:
只要对于任意一个G的某种组合,它是gcd的一个倍数,则为Y
下面我们考虑如何找出G的所有组合
题目中给出了,我们不妨考虑根号优化,至多有不超过根号n种G[i],我们统计每种G[i]的数量,对于每一种Gi,这是一个多重背包问题,我们不妨采用二进制优化。我们采用一个dp数组来记录每一种状态是否可以,对于一个贡献为w的物品,dp|=dp<<w
对于dp[0],当且仅当存在0时,我们才可以选取一个st==0的集合,因为我们显然不能将所有的图纸都分给同一个人。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<functional>
#include<unordered_map>
#include<bitset>
#include<set>
using namespace std;
#define int long long
#define inf 0x3f3f3f3f
#define N 200005
struct point
{
int g;
int r;
};
point ps[N];
int gcd(int da, int xiao)
{
if (da < xiao)
{
swap(da, xiao);
}
int temp;
while (xiao != 0)
{
temp = da%xiao;
da = xiao;
xiao = temp;
}
return da;
}
int xx[N];
bitset<N>bt;
signed main(void)
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int n;
cin >> n;
if (n == 1)
{
cout << "N" << '\n';
}
else
{
int sum = 0;
int tmp = -inf;
for (int i = 1; i <= n; i++)
{
cin >> ps[i].g >> ps[i].r;
sum += ps[i].g;
if (tmp == -inf)
{
tmp = ps[i].r;
}
else
{
tmp = gcd(tmp, ps[i].r);
}
xx[ps[i].g]++;
}
bt[0]=1;
for (int i = 1; i <N; i++)
{
if (!xx[i])continue;
vector<int>vc;
for (int j = 1; xx[i]; j *= 2)
{
if (xx[i]>=j)
{
vc.push_back(j);
xx[i] -= j;
}
else
{
vc.push_back(xx[i]);
break;
}
}
for (int j = 0; j < vc.size(); j++)
{
bt |= bt << (vc[j] * i);
}
bt[0] = (xx[0]>0);
}
int ans = 0;
for (int i = 0; i < sum; i++)
{
if (bt[i] && ((sum - i * 2) % tmp == 0))
{
ans = 1;
break;
}
}
if (ans)
{
cout << "Y" << '\n';
}
else
{
cout << "N" << '\n';
}
}
system("pause");
return 0;
}