Codeforces Round #818 (Div. 2) A~E解题报告
A. Madoka and Strange Thoughts
注意到3很小,那么可以直接讨论\(lcm(a,b)=\)(1或2或3)\(\times gcd(a,b)\)的情况
即a=b,a=2b,a=3b(我们假设a>b),然后因为钦定了a>b,后两种情况*2即可
void solve() {
cin >> n;
ll ans=n+2*(n/2+n/3);
cout << ans << endl;
}
B. Madoka and Underground Competitions
只需要考虑k*k的矩阵中的构造方案然后复制填充即可
因为钦点了(r,c)必须填充,不妨从这里开始填充,按照45度向下的方向填充即可,把矩阵变成(0,0)到(k-1,k-1)会比较方便取模。
int n, k, r, c;
char ans[510][510], s[510][510];
void solve() {
cin >> n >> k >> r >> c;
--r; --c;
r %= k; c %= k;
for(int i = 0; i < k; ++i) {
for(int j = 0; j < k; ++j) ans[i][j] = '.';
}
for(int i = 0; i < k; ++i) {
ans[r][c] = 'X';
++r; ++c;
r %= k; c %= k;
}
for(int a = 1; a <= n / k; ++a) {
for(int b = 1; b <= n / k; ++b) {
for(int i = 0; i < k; ++i) {
for(int j = 0; j < k; ++j) {
int x = 0, y = 0;
x = (a - 1) * k + i, y = (b - 1) * k + j;
s[x][y] = ans[i][j];
}
}
}
}
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) putchar(s[i][j]);
puts("");
}
}
C. Madoka and Formal Statement
首先有个显然的限制是\(a_i \leq b_i\)
然后因为每个数只能在\(a_i\le a_{i+1}\)时做加法,所以它的上限就是\(b_{i+1}+1\),如果\(b_i> b_{i+1}+1\),那显然不能构造出答案。
如果满足以上两个限制就可以构造出来了(手玩一下就知道了)
注意判定\(a_i=b_i\)的情况
void solve() {
cin >> n;
bool flag = 0;
for(int i = 1; i <= n; ++i) cin >> a[i];
for(int i = 1; i <= n; ++i) cin >> b[i];
for(int i = 1; i <= n; ++i)
if(a[i] != b[i]) flag = 1;
if(!flag) {
puts("Yes");
return;
}
flag = 0;
for(int i = 1; i <= n; ++i) {
if(a[i] <= b[i] && (a[i] == b[i] || b[i] <= b[i%n+1] + 1));
else flag = 1;
}
if(flag) puts("No");
else puts("Yes");
}
D. Madoka and The Corruption Scheme
vp的时候没有做出来,但是看完sol后发现整体思路还是比较自然的,只能说水平低了,复健还是没做好
把题意转化一下,就是一个有n层的完全二叉树,考虑你钦定的胜利边是黑边,失败是白,如果任何一个叶子到根的白边数量小于等于k,那么sponser就可以让他赢,所以就把这些点都填小的 其中最大的就是答案了
再把黑白转化成01,那么就是一个填数的问题,恰好有i条边就是\(i\choose n\),答案就是\(\sum_{i=0}^{\min{(n,k)}}{i\choose n}\)
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
int fac[N], ifac[N];
int n, k;
int power(int a, int b) {
int ans = 1;
while(b) {
if(b & 1) ans = 1ll * ans * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return ans;
}
int C(int n, int m) {
return 1ll*fac[m]*ifac[n]%mod*ifac[m-n]%mod;
}
signed main() {
cin >> n >> k;
fac[0] = 1;
for(int i = 1; i <= n; ++i) fac[i] = 1ll*fac[i-1]*i%mod;
ifac[n] = power(fac[n], mod - 2);
for(int i = n - 1; i >= 0; --i) ifac[i] = 1ll*ifac[i+1]*(i+1)%mod;
int ans = 0;
ifac[0] = 1;
for(int i = 0; i <= min(n, k); ++i) {
ans = (ans + C(i, n)) % mod;
ans = (ans + mod) % mod;
}
printf("%d\n", ans);
return 0;
}
E. Madoka and The Best University
死去的数论记忆忽然攻击我
首先知道\(\gcd(a,b)=\gcd(a,a-b)\),那么也等价于\(\gcd(a,b)=\gcd(a,a+b)\),在本题中就是\(\gcd(a,b)=\gcd(a,a+b)=\gcd(a,n-c)\)
不妨令\(d=\gcd(a,b)\),则有\(d|n-c\)此时枚举c并枚举gcd就是一个很可以接受的选择了,考虑有多少个\((a,b)\)满足a,b互质且\(d\times (a+b)=n-c\),显然这就是\(\varphi(\frac{n-c}{d})\),预处理phi就可以了
复杂度是\(O(n\log^2 n)\),实际上远跑不满
一开始phi的线性筛还写错了(悲,真得复健
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const ll mod = 1e9 + 7;
int n;
int p[N], vis[N];
ll phi[N];
vector<int>d[N];
ll lcm(int a, int b) {
return a/__gcd(a,b)*b%mod;
}
int main() {
cin >> n;
for(int i = 2; i <= n; ++i) {
if(!vis[i]) p[++p[0]] = i, phi[i] = i-1;
for(int j=1;j<=p[0]&&1ll*i*p[j]<=n;++j){
vis[i*p[j]]=1;
if(i%p[j]==0){
phi[i*p[j]]=phi[i]*p[j]%mod;
break;
}
phi[i*p[j]]=phi[i]*(p[j]-1)%mod;
}
}
for(int i=1;i<=n;++i){
for(int j=i;j<=n;j+=i)d[j].push_back(i);
}
ll ans=0;
for(int i=1;i<n-1;++i){
for(auto j:d[n-i]) {
(ans += lcm(i,j)*phi[(n-i)/j]%mod)%=mod;
}
}
cout<<(ans+mod)%mod;
}