Codeforces Round #678 (Div. 2)
CF1436A Reorder
分析
实际上只要让总和等于阈值就可以了
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
signed main(){
for (rr int T=iut();T;--T){
rr int n=iut(),m=iut(),sum=0;
for (rr int i=1;i<=n;++i) sum+=iut();
if (sum==m) printf("YES\n");
else printf("NO\n");
}
return 0;
}
CF1436B Prime Square
分析
考虑每行每列恰好有两个1就可以了
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
int a[101][101],n;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
signed main(){
for (rr int T=iut();T;--T){
n=iut(),a[n][1]=a[n][n]=1;
for (rr int i=1;i<n;++i) a[i][i]=a[i][i+1]=1;
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=n;++j)
print(a[i][j]),putchar(j==n?10:32);
a[n][1]=a[n][n]=0;
for (rr int i=1;i<n;++i) a[i][i]=a[i][i+1]=0;
}
return 0;
}
CF1436C Binary Search
分析
由于二分的序列是无序的,考虑实际上要想找到只需要二分的\(mid\)的位置有序就行了,
那么在二分时需要记录多少个关键数比\(x\)小,多少个关键数比\(x\)大,那么答案就是
\[P(x-1,less)*P(n-x,more)*(n-less-more-1)!
\]
代码
#include <cstdio>
#define rr register
using namespace std;
const int mod=1000000007;
int n,x,pos,fac[2011],inv[2011],ans1,ans2;
inline signed P(int n,int m){return 1ll*fac[n]*inv[n-m]%mod;}
signed main(){
scanf("%d%d%d",&n,&x,&pos),
fac[0]=fac[1]=inv[0]=inv[1]=1;
for (rr int i=2;i<=n;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for (rr int i=2;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
rr int L=0,R=n;
while (L<R){
rr int mid=(L+R)>>1;
if (mid>pos) ++ans2,R=mid;
else ans1+=(pos>mid),L=mid+1;
}
return !printf("%lld",1ll*P(x-1,ans1)*P(n-x,ans2)%mod*fac[n-ans1-ans2-1]%mod);
}
CF1436D Bandit in a City
分析
考虑树形dp,那么\(dp[x]=\max_{y\in son}\{dp[y]\}\)
但这显然不够,还要考虑将\(x\)上的值划分,那么最理想的状态显然是\(\lceil\frac{sum[x]}{sumleaf[x]}\rceil\),
然而这个最理想的状态不一定取得到,所以要与刚刚取个max
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=200011; typedef long long lll;
struct node{int y,next;}e[N];
int n,et,as[N],leaf[N]; lll a[N],dp[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline lll max(lll a,lll b){return a>b?a:b;}
inline void dfs(int x){
for (rr int i=as[x];i;i=e[i].next){
dfs(e[i].y),dp[x]=max(dp[x],dp[e[i].y]),
leaf[x]+=leaf[e[i].y],a[x]+=a[e[i].y];
}
dp[x]=max(dp[x],(a[x]+leaf[x]-1)/leaf[x]);
}
signed main(){
n=iut();
for (rr int i=1;i<=n;++i) leaf[i]=1;
for (rr int i=2;i<=n;++i){
rr int x=iut(); leaf[x]=0;
e[++et]=(node){i,as[x]},as[x]=et;
}
for (rr int i=1;i<=n;++i) a[i]=iut();
dfs(1);
return !printf("%lld",dp[1]);
}
CF1436E Complicated Computations
分析
考虑\(n+1\)对mex做出贡献当且仅当存在一段满足两个\(n+1\)的位置之间包含所有\(1\sim n\)的数,
考虑用权值线段树维护每个数的位置的最小值,然后最后还要特判一下
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100011;
int w[N<<2],a[N],v[N],last[N],n,ans;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline signed min(int a,int b){return a<b?a:b;}
inline void update(int k,int l,int r,int x,int y){
if (l==r){w[k]=y; return;}
rr int mid=(l+r)>>1;
if (x<=mid) update(k<<1,l,mid,x,y);
else update(k<<1|1,mid+1,r,x,y);
w[k]=min(w[k<<1],w[k<<1|1]);
}
inline signed query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return w[k];
rr int mid=(l+r)>>1;
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return min(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
signed main(){
n=iut();
for (rr int i=1;i<=n;++i) a[i]=iut();
for (rr int i=1;i<=n;++i){
if (a[i]>1) v[1]=1;
if (a[i]>1&&query(1,1,n,1,a[i]-1)>last[a[i]]) v[a[i]]=1;
last[a[i]]=i,update(1,1,n,a[i],i);
}
for (rr int i=2;i<n+2;++i)
if (query(1,1,n,1,i-1)>last[i])
v[i]=1;
for (ans=1;v[ans];++ans);
return !printf("%d",ans);
}
CF1436F Sum Over Subsets
分析
gcd=1显然通过容斥实现,记录约数为\(i\)的数的个数,
分类讨论一下,考虑\(x^2\)的贡献就是选择其它数删掉,
那也就是\(2^{cnt-2}(cnt-1)x^2\)
考虑\(xy\)的贡献,那就是挑其它数删掉或者是删掉其中一个数,
那也就是\(xy(2^{cnt-3}*(cnt-2)+2^{cnt-2})\)
那么\(x^2\)和\(xy\)可以分别用\(cntx^2,cntx\)跑Dirichlet 前缀和
\(xy\)也就是一次项的平方减去二次项,用光速幂可以做到\(O(mx\log_2mx)\)
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int p=31601,mod=998244353,N=100011; long long f0[N];
int two[p|31],pwo[p|31],mx,f1[N],f2[N],dp[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline signed Get(long long x){
x%=mod-1;
return 1ll*pwo[x/p]*two[x%p]%mod;
}
signed main(){
two[0]=pwo[0]=1;
for (rr int i=1;i<=p;++i) two[i]=mo(two[i-1],two[i-1]);
for (rr int i=1;i<=p;++i) pwo[i]=1ll*pwo[i-1]*two[p]%mod;
for (rr int n=iut();n;--n){
rr int x=iut(),c=iut(); if (mx<x) mx=x;
f0[x]=c,f1[x]=1ll*x*c%mod,f2[x]=1ll*f1[x]*x%mod;
}
for (rr int i=1;i<=mx;++i)
for (rr int j=i<<1;j<=mx;j+=i)
f0[i]+=f0[j],
f1[i]=mo(f1[i],f1[j]),
f2[i]=mo(f2[i],f2[j]);
for (rr int i=1;i<=mx;++i){
if (f0[i]<2) continue;
dp[i]=1ll*f2[i]*Get(f0[i]-2)%mod*mo(f0[i]%mod,mod-1)%mod;
rr int now=mo(1ll*f1[i]*f1[i]%mod,mod-f2[i]);
dp[i]=mo(dp[i],1ll*now*Get(f0[i]-2)%mod);
if (f0[i]>2) dp[i]=mo(dp[i],1ll*now*Get(f0[i]-3)%mod*mo(f0[i]%mod,mod-2)%mod);
}
for (rr int i=mx>>1;i;--i)
for (rr int j=i<<1;j<=mx;j+=i)
dp[i]=mo(dp[i],mod-dp[j]);
return !printf("%d",dp[1]);
}