4月做题记录

省选惨败,决定发奋。

AT2044 [AGC004D] Teleporter

发现1只能连自己,若非,则\(a[1]\rightarrow 1\)的链上均不合法。

题意转化为改变最少的连边使树的深度不超过\(m\),简单\(dp\)即可。

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
int n,m,a[maxn],cnt,f[maxn];
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int beg[maxn],nex[maxn],to[maxn],e;
inline void add(int x,int y){
	e++;nex[e]=beg[x];
	beg[x]=e;to[e]=y;
}
inline void dfs(int x,int fa){
	for(int i=beg[x];i;i=nex[i]){
		int t=to[i];
		if(t==fa)continue;
		dfs(t,x);
		f[x]=max(f[x],f[t]+1);
	}
	if(f[x]==m-1&&x!=1&&a[x]!=1){
		cnt++;f[x]=-1;
	}
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)
		a[i]=read();
	if(a[1]>1)cnt=1;
	for(int i=2;i<=n;i++)
		add(a[i],i);
	dfs(1,0);
	printf("%d\n",cnt);
	return 0;
}

AT2163 [AGC006B] Median Pyramid Easy

发现性质:若有两个连续的相同的数,则这两个数可以一直保持。

故将顶点的数放在最中间,构造下一行有两个这样的数在中间且在一起就好了。

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
int n,tp,a[maxn],vis[maxn],pos=1;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int main(){
	n=read(),tp=read();
	if(tp==1||tp==2*n-1)return puts("No"),0;
	puts("Yes");
	if(n==2)return printf("1\n2\n3\n"),0;
	a[n]=tp;vis[tp]=1;
	if(tp==2){
		a[n-1]=1;a[n-2]=4;a[n+1]=3;
		vis[1]=vis[3]=vis[4]=1;
	}else if(tp==2*n-2){
		a[n-1]=2*n-1;a[n-2]=2*n-4;a[n+1]=2*n-3;
		vis[2*n-1]=vis[2*n-3]=vis[2*n-4]=1;
	}else{
		a[n-1]=tp-1;a[n-2]=tp+2;a[n+1]=tp+1;
		vis[tp-1]=vis[tp+1]=vis[tp+2]=1;
	}
	for(int i=1;i<=2*n-1;i++){
		if(a[i])continue;
		while(vis[pos])pos++;
		a[i]=pos;vis[pos]=1;
	}
	for(int i=1;i<=2*n-1;i++)
		printf("%d\n",a[i]);
	return 0;
}

AT2164 [AGC006C] Rabbit Exercise

考虑\(a_i\)即为期望,则转移显然\(a_i=a_{i-1}+a_{i+1}-a_i\)

由于\(k\le 10^{18}\),考虑倍增。而\(m\le 10^5\),矩乘不现实。

考虑差分,\(d_i=a_i-a_{i-1}\),修改后\(d_i=a_{i-1}+a_{i+1}-a_i-a_{i-1}=a_{i+1}-a_i=d_{i+1}\quad d_{i+1}=a_{i+1}-a_{i-1}-a_{i+1}+a_i=a_i-a_{i-1}=d_i\)

则一次操作相当于交换\(d_i\)\(d_{i+1}\),倍增即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
const int mod=1e9+7;
int n,m,k,a[maxn],b[maxn],p[maxn],d[maxn],tmp[maxn];
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++)
		a[i]=read(),p[i]=b[i]=i;
	m=read(),k=read();
	for(int i=1,x;i<=m;i++)
		x=read(),swap(p[x],p[x+1]);
	while(k){
		if(k&1){
			for(int i=1;i<=n;i++)tmp[i]=b[p[i]];
			for(int i=1;i<=n;i++)b[i]=tmp[i];
		}
		for(int i=1;i<=n;i++)tmp[i]=p[p[i]];
		for(int i=1;i<=n;i++)p[i]=tmp[i];
		k>>=1;
	}
	for(int i=1;i<=n;i++)
		d[i]=a[b[i]]-a[b[i]-1]+d[i-1];
	for(int i=1;i<=n;i++)
		printf("%lld\n",d[i]);
	return 0;
}

真搞不懂这个差分是怎么想到的。

CF585E Present for Vitalik the Philatelist

学会新科技:狄利克雷前缀和、后缀和以及逆操作。

易知,只要满足\(\gcd(x,\gcd{S})=1\)\(\gcd{S}>1\)则有\(x\notin {S}\)。考虑设\(f_i\)代表集合中与\(i\)互质的数的个数,\(g_i\)\(\gcd\)恰好为\(i\)的子集个数,则答案为\(\sum f_i g_i\)

考虑求\(f_n=\sum\limits_{i=1}^n [\gcd(i,n)=1] c_i=\sum\limits_{i=1}^n c_i \sum\limits_{d|{\gcd(i,n)}}\mu(i)=\sum\limits_{i|n}\mu(i)\sum\limits_{i|d}c_d\)\(\text{dirichlet}\)前后缀合处理即可。

考虑求\(g_i\),恰好不好求,则转求\(\{p_i\}\)\(\gcd\)\(i\)的倍数的子集个数,由于每个数必为\(i\)的倍数,则\(p_i=2^{\sum\limits_{i|d}c_d}-1\)

由于\(p_i=\sum\limits_{d|i} g_i\),故对其做一次逆操作即可。时间复杂度\(\Theta(N\log\log N)\),其中\(N\)\(a_i\)最大值。

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
const int N=1e7+10;
const int mod=1e9+7;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int pri[N/10],tot,mu[N];bool flag[N];
int n,lim,c[N],g[N],s[N],p[maxn],ans;
int main(){
	n=read();
	for(int i=1,x;i<=n;i++)
		x=read(),lim=max(lim,x),c[x]++;
	mu[1]=p[0]=1;
	for(int i=2;i<=lim;i++){
		if(!flag[i])pri[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&i*pri[j]<=lim;j++){
			flag[i*pri[j]]=1;
			if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(int i=1;i<=tot;i++)
		for(int j=lim/pri[i];j;j--)
			c[j]+=c[j*pri[i]];
	for(int i=1;i<=lim;i++)
		g[i]=c[i]*mu[i];
	for(int i=1;i<=tot;i++)
		for(int j=1;j*pri[i]<=lim;j++)
			g[j*pri[i]]+=g[j];
	for(int i=1;i<=n;i++)
		p[i]=2ll*p[i-1]%mod;
	for(int i=1;i<=lim;i++)
		s[i]=p[c[i]]-1;
	for(int i=tot;i;i--)
		for(int j=1;j*pri[i]<=lim;j++)
			s[j]=(s[j]-s[j*pri[i]]+mod)%mod;
	for(int i=2;i<=lim;i++)
		ans=(ans+1ll*g[i]*s[i]%mod)%mod;
	printf("%d\n",ans);
	return 0;
}

P6810 「MCOI-02」Convex Hull 凸包

直接暴力反演+后缀和+卷积即可。注意\(d * \mu = 1\)

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e6+10;
int n,m,mod,ans;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int pri[maxn],tot,mu[maxn],flag[maxn];
int val[maxn],a[maxn],b[maxn],d[maxn];
int main(){
	n=read(),m=read(),mod=read();
	if(n>m)swap(n,m);
	mu[1]=1;
	for(int i=2;i<=m;i++){
		if(!flag[i])pri[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&i*pri[j]<=m;j++){
			flag[i*pri[j]]=1;
			if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(int i=1;i<=m;i++)
		for(int j=i;j<=m;j+=i)val[j]++;
	for(int i=1;i<=n;i++)a[i]=val[i];
	for(int i=1;i<=tot;i++)
		for(int j=n/pri[i];j;j--)
			a[j]=(a[j]+a[j*pri[i]])%mod;
	for(int i=1;i<=m;i++)b[i]=val[i];
	for(int i=1;i<=tot;i++)
		for(int j=m/pri[i];j;j--)
			b[j]=(b[j]+b[j*pri[i]])%mod;
	for(int i=1;i<=n;i++)
		for(int j=i;j<=n;j+=i)
			d[j]=(d[j]+val[i]*mu[j/i])%mod;
	for(int i=1;i<=n;i++)
		ans=(ans+1ll*a[i]*b[i]%mod*d[i]%mod)%mod;
	printf("%d\n",(ans+mod)%mod);
	return 0;
}

P5218 无聊的水题 II

\(\text{bezout}\)定理,显然集合\(\{S\}\)满足条件当且仅当\(\gcd(\{S\})=1\),令\(T=\{1,2,...,n\}\)

\(\sum\limits_{S\in T} [\gcd(\{S\})=1]=\sum\limits_{S\in T} \sum\limits_{d|\gcd(\{S\})}\mu(d)=\sum\limits_{d=1}^n \mu(d) \sum\limits_{S \in T , d|\gcd(\{S\}} 1=\sum\limits_{d=1}^n \mu(d)(2^{[\frac{n}{d}]}-1)\)

杜教筛即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e7;
const int mod=1e9+7;
int n,pri[N+5],tot,flag[N+5],ans;
int mu[N+5];map<int,int>f;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
inline int ksm(int x,int y){
	int res=1;
	while(y){
		if(y&1)res=res*x%mod;
		x=x*x%mod;y>>=1;
	}
	return res;
}
inline int sum(int n){
	if(n<=N)return mu[n];
	if(f[n])return f[n];
	int ans=1;
	for(int l=2,r;l<=n;l=r+1){
		r=n/(n/l);
		ans=(ans-(r-l+1)*sum(n/l)%mod+mod)%mod;
	}
	return f[n]=ans;
}
signed main(){
	mu[1]=1;
	for(int i=2;i<=N;i++){
		if(!flag[i])pri[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&i*pri[j]<=N;j++){
			flag[i*pri[j]]=1;
			if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(int i=1;i<=N;i++)mu[i]+=mu[i-1];
	n=read();
	for(int l=1,r;l<=n;l=r+1){
		r=n/(n/l);
		ans=(ans+(ksm(2,n/l)-1)*(sum(r)-sum(l-1))%mod)%mod;
	}
	printf("%lld\n",(ans+mod)%mod);
	return 0;
}

CF1278F Cards

想法和P4948 数列求和一样,列式子裂项递推即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=5e3+10;
const int mod=998244353;
int n,m,k,ans,a,b;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int c[maxn][maxn],f[maxn];
inline int ksm(int x,int y){
	int res=1;
	while(y){
		if(y&1)res=res*x%mod;
		x=x*x%mod;y>>=1;
	}
	return res;
}
signed main(){
	n=read(),m=read(),k=read();
	if(m==1)return printf("%lld\n",n),0;
	a=ksm(m-1,mod-2),b=ksm(a+1,mod-2);
	c[0][0]=1;f[0]=ksm(a+1,n);
	for(int i=1;i<=k;i++){
		c[i][0]=1;
		for(int j=1;j<=i;j++)
			c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
	}
	for(int i=1;i<=k;i++){
		int t1=0,t2=0;
		for(int j=0;j<=i-1;j++)
			t1=(t1+c[i-1][j]*f[j]%mod)%mod;
		for(int j=0;j<=i-2;j++)
			t2=(t2+c[i-1][j]*f[j+1]%mod)%mod;
		f[i]=a*b%mod*(n*t1%mod-t2+mod)%mod;
	}
	printf("%lld\n",f[k]*ksm(m-1,n)%mod*ksm(ksm(m,mod-2),n)%mod);
	return 0;
}

CF932E Team Work

由上一题改几个字就过了,不放代码。

P4053 [JSOI2007]建筑抢修

套路反悔贪心,按截止时间排序,不断放小的进去。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
const int mod=1e9+7;
int n,ans,tot;
struct node{int a,b;}p[maxn];
inline int cmp(node x,node y){return x.b<y.b;}
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
priority_queue<int>q;
signed main(){
	n=read();
	for(int i=1;i<=n;i++)
		p[i].a=read(),p[i].b=read();
	sort(p+1,p+1+n,cmp);
	for(int i=1;i<=n;i++)
		if(tot+p[i].a<=p[i].b){
			tot+=p[i].a;ans++;
			q.push(p[i].a);
		}else if(p[i].a<q.top()){
			tot-=q.top();q.pop();
			q.push(p[i].a);tot+=p[i].a;
		}
	printf("%lld\n",ans);
	return 0;
}

CF730I Olympiad in Programming and Sports

套路费用流,难怪评分低……

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define inf 0x7f
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int maxn=1e5+100;
int beg[maxn],nex[maxn],to[maxn],f[maxn],c[maxn],e,mf,mc;
void add(int x,int y,int z,int d){
	nex[e]=beg[x];beg[x]=e;
	to[e]=y;f[e]=z;c[e]=d;e++;
}
int n,m,st,ed,dis[maxn],vis[maxn],pre[maxn],val[maxn],flow[maxn];
queue<int>q;
int spfa(){
	memset(dis,inf,sizeof(dis));
	memset(flow,inf,sizeof(flow));
	memset(vis,0,sizeof(vis));
	dis[st]=0;pre[ed]=-1;vis[st]=1;
	q.push(st);
	while(!q.empty()){
		int x=q.front();
		q.pop();
		vis[x]=0;
		for(int i=beg[x];~i;i=nex[i]){
			int t=to[i];
			if(f[i]&&dis[t]>dis[x]+c[i]){
				dis[t]=dis[x]+c[i];
				pre[t]=x;val[t]=i;
				flow[t]=min(flow[x],f[i]);
				if(!vis[t]){
					vis[t]=1;
					q.push(t);
				}
			}
		}
	}
	return pre[ed]!=-1;
}
int a[maxn],b[maxn],cnt,f1,f2,p1,p2;
inline void Add(int x,int y,int z,int d){add(x,y,z,d),add(y,x,0,-d);}
signed main(){
	memset(beg,-1,sizeof(beg));
	n=read(),f1=read(),f2=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=n;i++)b[i]=read();
	cnt=n;st=++cnt;ed=++cnt;p1=++cnt;p2=++cnt;
	Add(st,p1,f1,0);Add(st,p2,f2,0);
	for(int i=1;i<=n;i++){
		Add(p1,i,1,-a[i]);Add(p2,i,1,-b[i]);
		Add(i,ed,1,0);
	}
	while(spfa()){
		int now=ed;
        mf+=flow[ed];
        mc+=flow[ed]*dis[ed];
        while(now!=st){
            f[val[now]]-=flow[ed];
            f[val[now]^1]+=flow[ed];
            now=pre[now];
        }
	}
	printf("%lld\n",-mc);
	for(int i=1;i<=n;i++)
		for(int j=beg[i];~j;j=nex[j])
			if(f[j]&&to[j]==p1)printf("%lld ",i);
	puts("");
	for(int i=1;i<=n;i++)
		for(int j=beg[i];~j;j=nex[j])
			if(f[j]&&to[j]==p2)printf("%lld ",i);
	puts("");
	return 0;
}

CF839D Winter is here

一开始把题看错了,折腾了好一会

\(\sum\limits_{S} |S|\gcd S=\sum\limits_{d>1} |S|d[\gcd S=d]=\sum\limits_{d>1} d \sum\limits_{S} |S| \sum\limits_{di|\gcd S} \mu(i)=\sum\limits_{S} |S|\sum\limits_{t|\gcd}\sum\limits_{d|t,d>1}d\mu(\frac{t}{d})=\sum\limits_{t}(\sum\limits_{d|t,d>1}d\mu(\frac{t}{d}))(\sum\limits_{t|\gcd S}|S|)\)

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
const int inv2=(mod+1)/2;
const int N=1e6;
int n,ans,p[maxn],pri[maxn],tot,flag[N+5];
int mu[N+5],b[N+5],a[N+5];
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)a[read()]++;
	mu[1]=p[0]=1;
	for(int i=1;i<=n;i++)p[i]=2ll*p[i-1]%mod;
	for(int i=2;i<=N;i++){
		if(!flag[i])pri[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&i*pri[j]<=N;j++){
			flag[i*pri[j]]=1;
			if(i%pri[j]==0){
				mu[i*pri[j]]=0;
				break;
			}
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(int i=2;i<=N;i++)
		for(int j=i;j<=N;j+=i)
			b[j]=(b[j]+mu[j/i]*i)%mod;
	for(int i=1;i<=tot;i++)
		for(int j=N/pri[i];j;j--)
			a[j]=(a[j]+a[pri[i]*j])%mod;
	for(int i=2;i<=N;i++)
		if(a[i])ans=(ans+1ll*p[a[i]-1]*a[i]%mod*b[i]%mod)%mod;
	printf("%d\n",(ans+mod)%mod);
	return 0;
}

CF301E Yaroslav and Arrangements

\(dp\)思路很显然,但我就是想不到。写了一片题解

#include <bits/stdc++.h>
#define ll long long
#define mod 1000000007
#define N 109
using namespace std;
int c[N][N],n,m,K,dp[2][N][N][N],ans;
void add(int &x,int y){x=(x+y>=mod)?x+y-mod:x+y;}
int main(){
	cin>>n>>m>>K;n++;
	c[0][0]=1;
	for(int i=1;i<=K;i++)
		for(int j=0;j<=i;j++){
			c[i][j]=(j?c[i-1][j-1]:0)+c[i-1][j];
			if(c[i][j]>K)c[i][j]=K+1;
		}
	int now=1,las=0;
	dp[now][0][1][1]=1;
	for(int i=1;i<=m;i++){
		las=now,now^=1;
		memset(dp[now],0,sizeof(dp[now]));
		for(int j=0;j<=n;j++)
			for(int k=1;k<=n;k++)
				for(int l=1;l<=K;l++)
					if(dp[las][j][k][l])
						for(int t=k;t<=n-j;t++)
							if(l*c[t-1][k-1]<=K)
								add(dp[now][j+t][t-k][l*c[t-1][k-1]],dp[las][j][k][l]);
		int tmp=0;
		for(int j=2;j<=n;j++)
			for(int l=1;l<=K;l++)add(tmp,dp[now][j][0][l]);
		add(ans,(ll)tmp*(m-i+1)%mod);
	}
	cout<<ans<<'\n';
	return 0;
}

CF309B Context Advertising

第一眼:\(n\)个数,按顺序取,分\(a\)段,每段中取最多权值和不超过\(b\)的个数和的最大值。只会\(n^2\log n\),评分2100?爬爬爬

第二眼:听说每行内的数要连续?还是不会,我菜了啊

第三眼:全文连续……这不是有什么好做的吗?预处理+倍增,\(\Theta(n\log n)\)

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=1e6+10;
const int mod=1e9+7;
int n,a,b,p[maxn],sum[maxn],nex[maxn][21],ans,l;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
string s[maxn];
int main(){
	n=read(),a=read(),b=read()+1;
	for(int i=1;i<=n;i++)
		cin>>s[i],p[i]=s[i].size()+1;
	for(int i=1;i<=n;i++)
		sum[i]=sum[i-1]+p[i];
	for(int i=1;i<=n;i++)
		nex[i][0]=upper_bound(sum+1,sum+n+1,sum[i-1]+b)-sum;
	nex[n+1][0]=n+1;
	for(int i=1;i<=20;i++)
		for(int j=1;j<=n+1;j++)
			nex[j][i]=nex[nex[j][i-1]][i-1];
	for(int i=1;i<=n;i++){
		int r=i;
		for(int j=0;j<=20;j++)
			if(a>>j&1)r=nex[r][j];
		if(ans<r-i)ans=r-i,l=i;
	}
	while(ans){
		for(int i=l;i<nex[l][0];i++)
			cout<<s[i]<<(i==nex[l][0]-1?'\n':' ');
		ans-=nex[l][0]-l;l=nex[l][0];
	}
	return 0;
}
posted @ 2021-04-11 22:48  syzf2222  阅读(72)  评论(0编辑  收藏  举报