Codeforces Round #678 (Div. 2)

CF1436A Reorder

洛谷传送门
CF1436A


分析

实际上只要让总和等于阈值就可以了


代码

#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

洛谷传送门
CF1436B


分析

考虑每行每列恰好有两个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

洛谷传送门
CF1436C


分析

由于二分的序列是无序的,考虑实际上要想找到只需要二分的\(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

洛谷传送门
CF1436D


分析

考虑树形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

洛谷传送门
CF1436E


分析

考虑\(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

洛谷传送门
CF1436F


分析

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]);
}
posted @ 2020-11-06 07:41  lemondinosaur  阅读(93)  评论(0编辑  收藏  举报