Codeforces Round #818 (Div. 2)

Codeforces Round #818 (Div. 2)

赛时

A B C D
7min 38min 57min 100min
+1 +1

基准分:\(\color{Blue}{1834}\)
排名:rk736
rating:\(\color{Cyan}{1439} \longrightarrow \color{Cyan}{1556}\)

\(\color{Gray}{1100}\) 卡半小时就 NM 离谱。
哦对着看错的题面搓了二十分钟啊,没事了。
为什么有人 D 会不加取模啊……
为什么 F 连着两次网络流啊……

A

CF1717A Madoka and Strange Thoughts

\(\color{Gray}{800}\)
对于 \(x\),答案只有可能是 \((x,2 \cdot x)\)\((x,3 \cdot x)\)
所以输出 \(n+2 \cdot \left( \left\lfloor\dfrac{n}{2}\right\rfloor + \left\lfloor\dfrac{n}{3}\right\rfloor \right)\) 即可。
时间复杂度:\(O(1)\)

void work(){cin>>n,cout<<n+(n/2)*2+(n/3)*2<<'\n';}

提交记录

B

CF1717B Madoka and Underground Competitions

\(\color{Gray}{1100}\)
就稍微倒退一下,循环每行要标记的的点即可。
反正就处理一下循环条件就行了,毕竟是 B 题。
时间复杂度:\(O(n \cdot m)\)

#define L(i,j,k) for(int i=(j);i<=(k);i++)
void work(){
  cin>>n>>k>>x>>y;
  int t=y%k;
  L(i,1,n) L(j,1,n) s[i][j]='.';
  L(i,0,n-1)
    for(int j=(t+i)%k;j<=n;j+=k)
      s[X(x+i)][j]='X';
  L(i,1,n){L(j,1,n) cout<<s[i][j];cout<<'\n';}
}

提交记录

C

CF1717C Madoka and Formal Statement

\(\color{ForestGreen}{1300}\)
手搓下样例就大概能知道些规律。
首先,如果出现 \(a_i>b_i\) 的情况就直接判为无解。
对于一个数 \(a_i\),如果要变成 \(b_i\),要么 \(a_i\) 本来就和 \(b_i\) 相等,否则就是通过 \(a_{i+1}\) 增值。
显然,\(a_i\) 最大只能增大到 \(b_{i+1 \bmod n} +1\),直接判断即可。
时间复杂度:\(O(n)\)

#define X(i) (i>n?i-n:(i<=0?i+n:i))
#define L(i,j,k) for(int i=(j);i<=(k);i++)
void work(){
  cin>>n;L(i,1,n) cin>>a[i];L(i,1,n) cin>>b[i];
  bool f=0;L(i,1,n) if(a[i]>b[i]) f=1;
  if(f) return cout<<"NO"<<'\n',void();
  L(i,1,n) if(b[i]>b[X(i+1)]+1&&a[i]!=b[i]) 
    return cout<<"NO"<<'\n',void();
  cout<<"YES"<<'\n';
}

提交记录

D

文字表述参考了 CF 上的讨论,这与我赛时做法基本一致,但得出思路的过程不同且其更具有参考价值,所以主要记录的是以上做法。

CF1717D Madoka and The Corruption Scheme

\(\color{Purple}{1900}\)
留个坑:因为答案等于 \(\left[ x^k \right] \dfrac{(1+x)^n}{1-x}\) 所以可以用 FFT 爆艹什么鬼

问题是在满二叉树上讨论的。
\(x\) 为当前 \(k\) 下,能保证无法获胜的人的个数,那么答案就是 \(2^n-x\)

然后本人的赛时做法就是找个 \(n=4\) 的状态手摸,发现了规律,然后写上去过了无比草率

尝试写个爆搜:

const int mod=1e9+7;
int ksm(int a,int b){
  int s=1;
  while(b){
    if(b&1) (s*=a)%=mod;
    (a*=a)%=mod;b>>=1;
  }return s;
}int solve(int n,int k){
  if(n<k||n<0) return 0;
  if(!k) return ksm(2,n);
  else return solve(n-1,k)+solve(n-1,k-1);
}

学过组合数学的话,可能会感觉上面的式子有点熟悉。

其实对于在二叉树上进行拓展的状态可以类比到杨辉三角上。
每次操作可以新增加的可控人数就是第 \(n\) 层的当前位的值。

或者,递推 \(n\) 的值,设之前一个推导的数 \(m\),其之间的差为 \(\dbinom{n-m-1}{k}\) 次。
因为每次的选择都会被确定,也不难得到上述式子。

所以,预处理组合数,随便选一种上述思路模拟即可。
别忘了加取模

时间复杂度:\(O(n)\)

#include <bits/stdc++.h>
#define int long long
#define L(i,j,k) for(int i=(j);i<=(k);i++)
const int N=1e5+100,mod=1e9+7;
int n,k;
int d[N],jc[N],inv[N];
void init(){
  d[0]=d[2]=1,d[1]=0;L(i,3,N-10) d[i]=(i-1)*(d[i-1]+d[i-2])%mod;
  jc[0]=1;L(i,1,N-10) jc[i]=jc[i-1]*i%mod;
  inv[1]=1;L(i,2,N-10) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
  inv[0]=1;L(i,1,N-10) inv[i]=inv[i-1]*inv[i]%mod;
}int C(int x,int y){return (jc[x]*inv[y]%mod*inv[x-y]%mod);}
int ksm(int a,int b){
  int s=1;
  while(b){
    if(b&1) (s*=a)%=mod;
    (a*=a)%=mod;b>>=1;
  }return s;
}void work(){
  cin>>n>>k;int sum=0;
  L(i,0,(min(n,k))) 
    (sum+=C(n,i))%=mod;
  cout<<sum;
}void work(){
  int ans=ksm(2,n);
  L(i,0,n) (ans-=ksm(2,i),C(n-i-1,k)-mod)%=mod;
  cout<<ans;
}signed main(){init();work();}

E

参考资料:OMG_wc(幻想家协会会长)的视频题解

CF1717E Madoka and The Best University

\(\color{Gold}{2200}\)

首先考虑暴力做法,直接枚举 \(a,b\),然后 \(c=n-a-b\),求出值后直接相加即可。时间复杂度:\(O(n^2 \log_2n)\)

换个思路,每次枚举 \(c\) 的值,此时 \(a+b=n-c\),很明显我们不能直接枚举 \(a,b\) 的值,那就直接枚举 \(\gcd(a,b)\) 的值。
\(x=a+b\),每次枚举的数是 \(t\),则 \(t|x\) 并且 \(\left( \dfrac{a}{t},\dfrac{b}{t} \right)=1\),辗转相除法推一步就可知 \(\left( \dfrac{a}{t},\dfrac{x}{t} \right)=1\)

此时 \(a\) 的取值个数也就是 \(a,b\) 的可取对数不难看出是 \(\phi \left( \dfrac{x}{t} \right)\),那就可以预处理出 \(\phi(i)\) 的值,然后做到每次 \(O(1)\) 查询。

此时的时间复杂度为:\(O(n)\) 枚举 \(c\) 的值,\(O(\sqrt{n})\) 枚举 \(c\) 的所有因数,\(\phi\) 的值可以 \(O(n)\)\(O \left( n \log_2 \left( \log_2 n \right) \right)\) 预处理出来。无耻宣博

时间复杂度:\(O(n\sqrt{n}\log_2n)\)

#define L(i,j,k) for(int (i)=(j);i<=(k);(i)++)
#define ll(i,j,k,l) for(int (i)=(j);i<=(k);(i)+=(l))
const int N=1e5+100;int n,p[N];
int lcm(int x,int y){return x*y/__gcd(x,y);}
void work(){
  cin>>n;int ans=0;L(i,1,n) p[i]=i;
  L(i,2,n) if(p[i]==i)
    ll(j,i,n,i) p[j]=p[j]/i*(i-1);
  L(i,1,n-2){
    int t=n-i;
    L(j,1,sqrt(t)) if(!(t%j)){
      (ans+=lcm(i,j)*p[t/j])%=mod;
      if(j!=1&&j!=t/j) (ans+=lcm(i,t/j)*p[j])%=mod;
    }
  }cout<<ans;
}

CF1717E Madoka and The Best University

\(\color{Red}{2500}\)
网络流。

posted @ 2022-09-09 16:11  AIskeleton  阅读(18)  评论(0编辑  收藏  举报