2021"MINIEYE杯"中超(6)补题
2021"MINIEYE杯"中超(6)
1001 Yes, Prime Minister
考虑区间和公式:(l + r) * (r - l + 1) / 2,当r >= l + 2时,这个公式一定可以写成两个大于1的数相乘,也就一定不是质数,所以在r > 0时,区间和长度一定不大于2。(l > 0 且r >= l + 2时)
对于x < 0 时,有两种情况:1.找到一个最小的y,使得y大于等于1 - x且y是质数,那么此时区间为[1 - y, y]。2.找到一个最小的z,使得区间和是质数,此时区间为[2 - z, z]
对于x > 0时,先考虑x是否是质数,再考虑是否可以与前或后相加是质数,如果都不行,则类比x < 0时的思路向负轴扩展。
如果l < 0, r > 0 那么[l, r] == [-l + 1, r]区间和相等。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e8 + 10;
int n;
bool st[N];
int cnt;
int primes[N];
vector<int> v;
int t;
void get_primes(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i, v.push_back((i + 1) / 2);
for (int j = 0; primes[j] <= n / i; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
int main()
{
get_primes(N - 1);
cin >> t;
while (t -- )
{
int x;
cin >> x;
if (x == 0) {puts("3"); continue;}
if (x == 1) {puts("2"); continue;}
if (x > 1 && !st[x]) puts("1");//x本身是质数,区间为1
else if (x + x + 1 > 1 && !st[x + x + 1] || x + x - 1 > 1 && !st[x + x - 1]) puts("2");//与前或者后结合是质数
else
{
long long ans = 0x3f3f3f3f;
if (x > 0)
{
int p = *lower_bound(primes, primes + cnt, x);
int z = *lower_bound(v.begin(), v.end(), x);
ans = min(ans, min(1ll * p * 2, 1ll * 2 * z - 1));
printf("%lld\n", ans);
}
else
{
int p = *lower_bound(primes, primes + cnt, 1 - x);
int z = *lower_bound(v.begin(), v.end(), 2 - x);
ans = min(ans, min(1ll * p * 2, 1ll * 2 * z - 1));
printf("%lld\n", ans);
}
}
}
return 0;
}
1004 Decomposition
所有边分成k个不相交的集合,显然按照欧拉回路构造是最优解。
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
vector<int> ege;
int case;
int n, k;
int t;
void solve()
{
cout << "Case #" << ++ case << ":" << endl;
ege.clear();
cin >> n >> k;
ege.pb(n - 1);
for(int i = 0;i <= n / 2;i ++)
{
int sgn = 1, now = i;
for(int j = 1;j < n;j ++)
{
ege.pb(now);
// 欧拉回路中交替构造边
now = (now + sgn * j + n - 1) % (n - 1);
sgn *= -1;
}
ege.pb(n - 1);
}
int now = 0;
while(k --)
{
int len;
cin >> len;
len ++;
while(len --) cout << ege[now ++ ] + 1 << (len ? ' ' : '\n');
now --;
}
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> t;
while (t -- ) solve();
return 0;
}
1005 Median
若干个中位数将1~n分成了若干个集合,任意两个集合中挑选两个数都可以消去,那么分两种情况。
1.集合长度最大的数的个数小于等于其他集合总和,那么到最后要么所有数字都匹配消除,要么还剩下一个,这个一个的所在集合我们可以任意选取,我们可以选取最大的那个数,然后把它放在中位数最小的集合中,符合题目要求。
2.集合长度最大的数的个数大于其他集合总和,那么到最后匹配后剩余的数字一定是出现在此集合中的,此时这些数如果放在中位数大于他们的集合中,会影响结果,所以只能放在前面,但是每个集合最多放一个这样的数字,所以这时候要判断中位数大小小于这些数的集合个数与剩余的数的个数的大小关系,可以全部放完才符合题意,不然输出NO。
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int t;
int n, m;
int a[N];
int b[N];
void solve()
{
cin >> n >> m;
for (int i = 1; i <= m; i ++ ) cin >> a[i];
sort(a + 1, a + m + 1);
int cnt = 1, mx = 0, sum = 0, num = 0;
for (int i = 1; i <= m; i ++ )
{
b[cnt] = a[i] - a[i - 1] - 1;
if (mx < b[cnt]) mx = b[cnt], num = i - 1;
sum += b[cnt];
cnt ++ ;
}
b[cnt ++ ] = n - a[m];
if (mx < b[cnt - 1]) mx = b[cnt - 1], num = m;
sum += b[cnt - 1];//统计被分开的区间中每个区间中的数字个数
//for (int i = 1; i < cnt; i ++ ) cout << b[i] << ' '; cout << endl;
//cout << mx << ' ' << num << endl;
if (mx <= sum - mx) puts("YES");
else
{
if (num >= mx - (sum - mx)) puts("YES");
else puts("NO");
}
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> t;
while (t -- ) solve();
return 0;
}