Codeforces Round #818 (Div. 2)
A
题意:求满足条件的整数数对(a,b).
-
\(1\leq a,b\leq n\)
-
\(\frac{lcm(a,b)}{gcd(a,b)} \leq3\)
核心思路:这个要求我们对gcd有个不错的理解,我们假设gcd(a,b)=t.那么a,b就三种取值情况。(t,t),(t,2*t),(t,3t).所以我们就把情况装变为求n中1的倍数,2的倍数,3的倍数。但是我们需要注意的是第二种和第三种情况可以颠倒顺序,所以可以需要乘2.
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+10, M = 600, MOD = 1e8;
char ch[M][M];
int main()
{
int t;
cin >> t;
while (t--)
{
LL n;
cin >> n;
cout << n + n/2*2 + n / 3 * 2 << endl;
}
}
B
题意:求在(r,c)处已经有一个X ,满足对于任意一个 k 长度的连续的格子都要至少有一个X的X 最少数量。保证n 是k 的倍数。
核心思路:我们要注意我们已经有一个点放了X,所以我们可以以这个点作为中心向四周辐射,这又是一个什么意思呢。就是我们构造一个长度为k的倍数的正方形,如果距离(r,c)是k的倍数,我们就往正方形的左上顶点放一个X。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+10, M = 600, MOD = 1e8;
char ch[M][M];
int main()
{
int t;
cin >> t;
while (t--)
{
int n, k, r, c;
cin >> n >> k >> r >> c;
for(int i=0;i<n;i++)
for (int j = 0;j < n;j++)
{
if (((i - r) - (j - c)) % k == 0)
ch[i][j] = 'X';
else
ch[i][j] = '.';
}
for (int i = 0;i < n;i++)
{
for (int j = 0;j < n;j++)
cout << ch[i][j];
cout << endl;
}
}
}
C
题意:给出a,b序列,如果\(a_i\le a_{(n+1)\%n}\),那么可以让\(a_i\)加1,询问是否可以操作使得a变成b
核心思路:首先考虑最容易的一种无解情况:\(a_i>b_i\).然后我们在考虑其他的情况。我们可以从需要构造的数组入手。
其实我们会发现\(b_{i+1}与b_i\)的差值超过一,那就肯定构造不出,因为需要满足前面比后面小才可以构造.
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+10, M = 11, MOD = 1e8;
int a[N], b[N];
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
int flag = 1;
for (int i = 0;i < n;i++)
cin >> a[i];
for (int i = 0;i < n;i++)
cin >> b[i];
for (int i = 0;i < n;i++)
{
if (a[i] > b[i])
flag = 0;
if (a[i] != b[i] && b[(i + 1) % n] + 1 < b[i])
flag = 0;
}
if (flag)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}
D
题意:就是m这个人他又决定比赛谁输谁赢的权利,但是同样的裁判方也有k次决定输赢的机会。m希望最后赢的人的编号经可能小,裁判则希望尽可能大。问最后的编号是多少。
核心思路: 先找一般的规律。如果裁判放一次都不修改,那么最后赢得肯定是1.我们转念一想如果希望\(2^n\)获胜,那么我们肯定需要修改n次。但是我们会发现这种情况只有一种,应为我们需要n场都输,所以就是\(C_{n}^{n}=1\),然后修改n-1次,就是\(C_{n}^{1}\),也即是n场里面赢一场。也就是编号较小的\(2^n-1,2^n-2\cdots2^n-n\),一共n位选手会在修改中获得冠军.接下来以此类推就会发现一般的规律。
但是这其中是参杂贪心的思想的,因为我们需要编号的上界尽可能地小,所以我们需要编号较大的都输掉比赛。
然后此时我们再回到赞助商的角度。如果一次都不修改那么肯定是1,修改一次至多1+\(C_{n}^{1}\),这里的\(C_{n}^{1}\)其实和我们上面递推的修改的次数与多少人可以在这次修改中获得冠军有关。修改两次就是\(1+C_{n}^{1}+C_{n}^{2}\).一次类推就好了。
组合数使用递推式求解就好了。因为数据范围并不是很大.
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+10, M = 600, mod = 1e9+7;
int fa[N], invfa[N];
LL qmi(LL a, LL b)
{
LL res = 1;
while (b)
{
if (b & 1)
res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void Init()
{
fa[0] = 1;
invfa[0] = 1;
for (int i = 1;i < N;i++)
{
fa[i] =(LL) fa[i - 1] * i%mod;
invfa[i] =(LL) invfa[i - 1] * qmi(i, mod - 2)%mod;
}
}
LL C(int a, int b)
{
return (LL)fa[a] * invfa[a - b] % mod * invfa[b] % mod;
}
void solve()
{
LL ans = 0;
int n, k;
cin >> n >> k;
for (int i = 0;i <= min(k,n);i++)
ans = (ans + C(n, i))%mod;
cout << ans << endl;
}
int main()
{
Init();
solve();
}
E
题意:就是一个公示的求解
核心思路:首先我们会发现一个比较棘手的问题,那就是这个这里有个三元不太好处理,但是我们可以利用a+b+c=n,把c使用a,b表示出来,我们先假设gcd(a,b)=i.那么\(a+b=i,2*i,3*i,4*i,\cdots,j*i\),所以我们枚举j就好了。 一旦j确定了,那么我们整个式子也确定了。因为我们gcd(a,b)是已经确定了的就是i。
但是我们还有需要确定的条件,那就是gcd(a/i,b/i)=1,令x=a/i,y=b/i.也就是x和y互质。所以我们把问题转换为x+y=j且x和y互质。
因为\(gcd(x,y)=gcd(x,j-x)=gcd(j,x)=1\),因为x<j,所以就是求x的取值个数中小于j且与j互质的数的个数,这个就是欧拉函数的定理。然后我们把我们枚举的lcm乘以这个种类数就好了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+10, M = 600, mod = 1e9+7;
int st[N], primes[N], phi[N];
int cnt;
void Init()
{
phi[1] = 1;
for (int i = 2;i < N;i++)
{
if (!st[i])
{
primes[cnt++] = i;
phi[i] = i - 1;
}
for (int j = 0;primes[j] * i < N;j++)
{
st[primes[j] * i] = 1;
if (i % primes[j] == 0)
{
phi[i * primes[j]] = phi[i] * primes[j];
break;
}
phi[i * primes[j]] = phi[i] * (primes[j] - 1);
}
}
}
LL gcd(LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b)
{
return (LL)a / gcd(a, b)*b % mod;
}
int main()
{
Init();
int n;
cin >> n;
LL ans = 0;
for(int i=1;i<=n;i++)
for (int j = 2 * i;j < n;j += i)
{
LL t = (LL)lcm(i, n - j) * phi[j / i]%mod;
ans = (ans + t) % mod;
}
cout << (ans%mod+mod)%mod;
}

浙公网安备 33010602011771号