题目链接:https://codeforces.com/contest/1780
解题思路:组合就是要么三个都是奇数,要么一个奇数,否则就是NO。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)|1
typedef long long ll;
const int mx = 3e5 + 10;
int a[mx];
vector<int> v[2];
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
v[0].clear();
v[1].clear();
for (int i=1;i<=n;i++) {
scanf("%d", a+i);
v[a[i]%2].push_back(i);
}
if (v[1].size() > 2) {
puts("YES");
printf("%d %d %d\n", v[1][0], v[1][1], v[1][2]);
} else if (v[1].size() && v[0].size() > 1){
puts("YES");
printf("%d %d %d\n", v[1][0], v[0][0], v[0][1]);
} else
puts("NO");
}
return 0;
}
解题思路:肯定是分成2半gcd值最大,设总和是sum,那么第一部分和第二部分的gcd是和sum的gcd是一样的,因为肯定是公约数。所以只要看sum和哪个前缀和gcd大就行了。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)|1
typedef long long ll;
const int mx = 3e5 + 10;
int a[mx];
ll sum[mx];
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
for (int i=1;i<=n;i++) {
scanf("%d", a+i);
sum[i] = sum[i-1] + a[i];
}
ll ma = 0;
for (int i=1;i<n;i++) {
ma = max(ma, __gcd(sum[i], sum[n]));
}
printf("%lld\n", ma);
}
return 0;
}
解题思路:(1)首先可以得出任意两个数的gcd不会大于r-l,假设gcd(l, r) = x > r - l,l = x * i,r = x * j。因为l != r,所以i != j, i < j,所以x * j - x * i >= x > r - l,两者互相矛盾。(2)还可以证明任意两个数的gcd肯定不大于r / 2。(3)令x = (r - l + 1) / 2,那么肯定存在1-x的gcd。因为肯定存在 l <= i * x < (i + 1) * x <= r。二者gcd为x。
另外一种通用的解求是否存在gcd有x,就有 l + 2 * x - l % x <= r,当l % x == 0时,式子为 l + x <= r。l + x - l % x就是求第一个能整除x的位置,l + 2 * x - l % x求第二能整除x的位置,二者gcd为x,因为二值肯定大于l,所以只要考虑小于等于r。从式子可知当x > l时,式子就为2 * x <= r。这个式子就很好求了。所以我们只要讨论x <= l的情况,因为l <= 1e9,并且我们是从(r - l + 1) / 2开始讨论的x,所以可以大概计算出,2 * l / (r - l + 1) = y这个因数并不会特别大。因为 (r - l +1)大,y就小。r - l +1小,那么我们就根据(1)直接暴力即可。接下来就需要考虑如果暴力枚举y,讲上面式子改为l + 2 * x - p <= r,令l = y * x + p。那么根据这个式子,x每+1,左边式子就要加y + 2,因为式子就会变成l + 2 * (x + 1) - p + y,令l + y * (x + 1) + p - y,因此在y相同的情况下,我们可以计算出有多少个x满足这个条件。然后去枚举每个y。直到y = 0,x > l为止。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)|1
typedef long long ll;
const int mx = 3e5 + 10;
int main() {
int t;
scanf("%d", &t);
while (t--) {
ll l, r;
scanf("%lld%lld", &l, &r);
ll ans = (r - l + 1) / 2;
ll x = (r - l + 1) / 2 + 1;
ll mi = min(l, r - l + 1);
while (x <= mi) {
ll m = l % x;
if (l % x == 0)
m = x;
ll left = l / x;
if (x * 2 <= r - l + m) {
ll temp = m / left;
if (m == x)
temp = 0;
if (m % left == 0)
temp = max(temp - 1, 0ll);
ll v1 = r - l + m - x * 2;
ll v2 = min(v1 / (left + 2), temp);
ans += v2 + 1;
x += temp;
}
x++;
}
ans += max(0ll, min(r/2, r - l + 1) - x + 1);
printf("%lld\n", ans);
}
return 0;
}
解题思路:先排个序,然后可以知道一个数最多的不同质因子个数是6。我们可以通过容斥法来减去前面有和当前位置相同质因子的值。就是每个位置当最大的数量了。时间复杂为
。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)|1
typedef long long ll;
const int mx = 3e5 + 10;
int a[mx];
bool vis[mx];
vector <int> pri;
pair <ll, int> val[mx];
void init()
{
for (int i=2;i<mx;i++) {
if (!vis[i]) {
pri.push_back(i);
}
for (int v: pri) {
if (v * i >= mx)
break;
vis[i * v] = 1;
if (i % v == 0)
break;
}
}
}
ll solve(vector<int> &tv, int idx, int vs, int fg, int ps) {
ll ans = fg * (1ll * val[vs].second * (ps - 1) - val[vs].first);
for (int i=idx; i<tv.size(); i++) {
ans += solve(tv, i + 1, vs * tv[i], -fg, ps);
val[vs * tv[i]].first += ps;
val[vs * tv[i]].second++;
}
return ans;
}
int main() {
init();
int n;
scanf("%d", &n);
for (int i=1;i<=n;i++) {
scanf("%d", a+i);
}
ll ans = 0, sum = 0;
sort(a + 1, a + 1 + n);
for (int i=1;i<=n;i++) {
vector <int> tv;
for (int v: pri) {
if (v * v > a[i])
break;
if (a[i] % v == 0) {
tv.push_back(v);
a[i] /= v;
while(a[i] % v == 0)
a[i] /= v;
}
}
if (a[i] != 1) tv.push_back(a[i]);
ans += sum - i + 1;
ans += solve(tv, 0, 1, 1, i);
sum += i;
}
printf("%lld\n", ans);
return 0;
}