思路:我们考虑如何求解,先考虑只有两栋楼,你要得到的是G1+R1*K1==G2+R2*K2,移项得:R1*K1-R2*K2==G2-G1,右边是常数,左边很经典就是ax+by,这个式子能组成的数字是gcd(x,y)的倍数,裴属定理证明的,然后我们可以扩展得到ax+by+cz+dp,这个可以得到的所有数字x满足x是gcd(x,y,z,p)的倍数,因此我们假设左边3个楼层为ax+w1,by+w2,cz+w3,令gc1=gcd(x,y,z),sumw=w1+w2+w3,能组成的高度和那么就是k*gc1+sumw,右边集合类似我们设为k2*gc2+sumw2,那么你要让k*gc1+sumw==k2*gc2+sumw2,移项得到k*gc1-k2*gc2==sumw2-sumw,这个左边也是ax+by,设u=gcd(gc1,gc2),能组成的也是u的倍数,因此答案应满足(sumw2-sumw) mod. u ==0那么你会发现,对于u来说是两个集合的gcd,那不就是总gcd,因此集合的划分不会影响这个,只会影响sumw和sumw2,因为1到2e5,那么直接枚举即可,当然前提是你枚举的这个sumw必须能被凑出来,那么我们可以01背包来求解嘛,但是n是2e5,值域也是2e5,那么会tle,我们发现和最多是2e5,那么不同种类的就最多根号级别个,就可以转化为多重背包,2进制优化再变为01背包,这是你的物品数最多就是sqrt(n)*log(sqrt(n)),就可以直接01背包搞了
diamond:
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
int g = 0, s = 0;
const int N = 2e5 + 10;
set<int> object;
vector<int> num(N);
for (int i = 1; i <= n; i ++) {
int G, R;
cin >> G >> R;
s += G;
g = gcd(R, g);
object.insert(G);
num[G] ++;
}
if (n == 1) {
cout << "N\n";
return 0;
}
vector<int> dp(s + 1);
dp[0] = 1;
for (auto &i : object) {
int has = num[i];
for (int k = 1; k <= has; k <<= 1) {
has -= k;
i64 w = k * i;
for (int j = s; j >= w; j --)
dp[j] |= dp[j - w];
}
if (has) {
i64 w = has * i;
for (int j = s; j >= w; j --)
dp[j] |= dp[j - w];
}
}
i64 ans = 0, f = object.count(0);
f ^= 1;
for (int i = f; i <= s - f; i ++) {
if (dp[i]) {
if (abs(s - 2 * i) % g == 0) {
cout << "Y\n";
return 0;
}
}
}
cout << "N\n";
return 0;
}