noip模拟38[这怕不是1/4???]

noip模拟38 solutions

我觉得吧,这次考试还是非常的容易,因为之前的[x,y,z][u,v,w]给我吓到了

所以我差点考场就切掉一个题,第二题属实是真的傻了

所以这一场除了最后一题难改,别的都挺简单的。

T1 a

简单来说就是一个双指针,就完事了

因为在每一行上,你左上端点的移动会导致右下端点的单调右移。

所以我们直接对每一行开两个指针,扫就行了

0的情况,只能特判,好像双指针不太行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=35;
const int M=5e4+5;
int n,m,l,r;
int jz[N][M],fro[N][M];
int pol[N],por[N];
ll ans;
signed main(){
	//cout<<"a"<<endl;
	scanf("%d%d",&n,&m);
	for(re i=1;i<=n;i++){
		char x[M];
		scanf("%s",x+1);
		for(re j=1;j<=m;j++){
			jz[i][j]=x[j]-'0';
			fro[i][j]=fro[i-1][j]+fro[i][j-1]-fro[i-1][j-1]+jz[i][j];
		}
	}
	scanf("%d%d",&l,&r);
	if(l==0&&r==n*m){
		for(re i=1;i<=n;i++){
			for(re j=1;j<=m;j++){
				ans+=1ll*(n-i+1)*(m-j+1);
			}
		}
		printf("%lld",ans);
		return 0;
	}
	for(re i=0;i<n;i++){
		memset(pol,0,sizeof(pol));
		memset(por,0,sizeof(por));
		for(re j=0;j<m;j++){
			for(re x=i+1;x<=n;x++){
				for(re y=pol[x];y<=m;y++){
					if(fro[x][y]-fro[x][j]-fro[i][y]+fro[i][j]>=l){
						pol[x]=y;break;
					}
					if(y==m)pol[x]=m+1;
				}
				for(re y=por[x]+1;y<=m;y++){
					if(fro[x][y]-fro[x][j]-fro[i][y]+fro[i][j]>r){
						por[x]=y-1;break;
					}
					if(y==m)por[x]=m;
				}
				if(pol[x]!=m+1)ans+=por[x]-pol[x]+1;
			}
		}
	}
	printf("%lld",ans);
}

T2 b

值域这么小!!!你竟然想不到要枚举值域????

确实我考场上就没有想到,

我们直接暴力容斥,就像题解上说的那样

时间复杂度我还是要证明一下

\(1+\frac{1}{2}+\frac{1}{3}+...+\frac{1}{n}=\ln{n}\)

这个就是调和级数,无穷级数的一种

我们还要枚举每一个n,所以总的时间复杂度就是\(\mathcal{O(n\ln{n})}\)

其实我们容斥的过程还可以用莫比乌斯反演来解释

如果有 \(f(n)=\sum_{n|d}g(d)\),那么有 \(g(n)=\sum_{n|d}\mu(\frac{d}{n})f(d)\)

直接得到对应的数量

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const ll mod=1e9+7;
const int N=25;
const int M=1e5+5;
int n,m,c[N][M],cnt[N][M];
ll ans,sum[M],maxn;
ll ksm(ll x,ll y){
	ll ret=1;
	while(y){
		if(y&1)ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}
signed main(){
	scanf("%d%d",&n,&m);
	for(re i=1;i<=n;i++)
		for(re j=1;j<=m;j++){
			ll a;scanf("%lld",&a);
			c[i][a]++;maxn=max(maxn,a);
		}
	for(re i=1;i<=n;i++)
		for(re j=1;j<=maxn;j++)
			for(re k=1;k*j<=maxn;k++)
				cnt[i][j]+=c[i][j*k];
	for(re j=maxn;j>=1;j--){
		sum[j]=1;
		for(re i=1;i<=n;i++)
			sum[j]=1ll*sum[j]*(cnt[i][j]+1)%mod;
		sum[j]=(sum[j]-1+mod)%mod;
		if(!sum[j])continue;
		for(re k=2;k*j<=maxn;k++)
			sum[j]=(sum[j]-sum[k*j]+mod)%mod;
		ans=(ans+sum[j]*j%mod)%mod;
	}
	printf("%lld",ans);
}

T3 c

话说这个题让我对点分治的理解又一步加深了,

原来还可以用来做dp

话说为啥只需要三个颜色就够了??因为我们之关心当前的颜色和两侧的关系

那么在多出一条不一样的就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
const int M=3e5+5;
int n,m,q;
vector<pair<int,int> > edg[N];
vector<pair<int,vector<int> > > g[N];
vector<int> vfa[N];
int dp[N][3][3];
struct QUS{
	int x,y,id;
	QUS(){}
	QUS(int a,int b,int c){
		x=a;y=b;id=c;
	}
};
vector<QUS> qus[N];
int ans[N];
void dfs_unique(int x,int f){
	sort(edg[x].begin(),edg[x].end());
	edg[x].erase(unique(edg[x].begin(),edg[x].end()),edg[x].end());
	for(re i=0,j;i<edg[x].size();i=j){
		int y=edg[x][i].first;j=i+1;
		while(edg[x][j].first==y&&j<edg[x].size())j++;
		if(y==f)continue;
		g[x].push_back(make_pair(y,vector<int>()));
		g[y].push_back(make_pair(x,vector<int>()));
		for(re k=i;k<j&&k<i+3;k++){
			g[x].back().second.push_back(edg[x][k].second);
			g[y].back().second.push_back(edg[x][k].second);
		}
		dfs_unique(y,x);
	}
}
bool vis[N];
int ms[N],siz[N],rt;
void get_rt(int x,int f,int tot){
	siz[x]=1;ms[x]=0;
	for(re i=0,y;i<g[x].size();i++){
		y=g[x][i].first;
		if(vis[y]||y==f)continue;
		get_rt(y,x,tot);
		siz[x]+=siz[y];
		ms[x]=max(ms[x],siz[y]);
	}
	ms[x]=max(ms[x],tot-siz[x]);
	if(ms[x]<=tot/2)rt=x;
}
int sfa[N][21],sdep[N];
void pre_sol(int x,int tot,int f){
	get_rt(x,0,tot);x=rt;
	//cout<<x<<" "<<f<<endl;
	vis[x]=true;
	sfa[x][0]=f;
	sdep[x]=sdep[sfa[x][0]]+1;
	//cout<<x<<" "<<sdep[x]<<endl;
	for(re i=1;i<=20;i++)sfa[x][i]=sfa[sfa[x][i-1]][i-1];
	for(re i=0,y;i<g[x].size();i++){
		y=g[x][i].first;
		if(vis[y]||y==f)continue;
		//get_siz(y,x);
		if(siz[y]<=siz[x])pre_sol(y,siz[y],x);
		else pre_sol(y,tot-siz[x],x);
	}
}
inline int LCA(int x,int y){
	//cout<<x<<" "<<y<<" "<<sdep[x]<<" "<<sdep[y]<<endl;
	if(sdep[x]<sdep[y])swap(x,y);
	for(re i=20;i>=0;i--){
		if(sdep[sfa[x][i]]>=sdep[y])
			x=sfa[x][i];
	}
	//cout<<x<<" "<<y<<" "<<endl;
	if(x==y)return x;
	for(re i=20;i>=0;i--){
		if(sfa[x][i]!=sfa[y][i])
			x=sfa[x][i],y=sfa[y][i];
	}
	return sfa[x][0];
}
int tmp[N];
void dfs_dp(int x,int f,int rt){
	tmp[x]=rt;
	for(re i=0,y;i<g[x].size();i++){
		y=g[x][i].first;
		if(vis[y]||y==f)continue;
		vfa[y]=g[x][i].second;
		for(re j=0;j<vfa[rt].size();j++){
			for(re k=0;k<vfa[y].size();k++){
				dp[y][j][k]=-1e9;
				for(re o=0;o<vfa[x].size();o++)
					dp[y][j][k]=max(dp[y][j][k],dp[x][j][o]+(vfa[x][o]!=vfa[y][k]));
			}
		}
		dfs_dp(y,x,rt);
	}
}
void get_ans(int x,int tot){
	get_rt(x,0,tot);x=rt;
	vis[x]=true;
	for(re i=0,y;i<g[x].size();i++){
		y=g[x][i].first;
		if(vis[y])continue;
		vfa[y]=g[x][i].second;
		for(re j=0;j<vfa[y].size();j++){
			for(re k=0;k<vfa[y].size();k++){
				if(j==k)dp[y][j][k]=1;
				else dp[y][j][k]=-1e9;
			}
		}
		dfs_dp(y,x,y);
	}
	for(re i=0,a,b;i<qus[x].size();i++){
		a=qus[x][i].x;b=qus[x][i].y;
		//cout<<a<<" "<<b<<endl;
		if(b==x)swap(a,b);
		if(a==b)ans[qus[x][i].id]=0;
		else if(a==x)
			for(re j=0;j<vfa[tmp[b]].size();j++)
				for(re k=0;k<vfa[b].size();k++)
					ans[qus[x][i].id]=max(ans[qus[x][i].id],dp[b][j][k]);
		else {
			for(re j=0;j<vfa[tmp[a]].size();j++)
				for(re k=0;k<vfa[a].size();k++)
					for(re p=0;p<vfa[tmp[b]].size();p++)
						for(re q=0;q<vfa[b].size();q++)
							ans[qus[x][i].id]=max(ans[qus[x][i].id],dp[a][j][k]+dp[b][p][q]-(vfa[tmp[a]][j]==vfa[tmp[b]][p]));
		}
	}
	for(re i=0,y;i<g[x].size();i++){
		y=g[x][i].first;
		if(vis[y])continue;
		//get_siz(y,x);
		if(siz[y]<=siz[x])get_ans(y,siz[y]);
		else get_ans(y,tot-siz[x]);
	}
}
signed main(){
	scanf("%d%d",&n,&m);
	for(re i=1;i<=m;i++){
		int x,y,z;scanf("%d%d%d",&x,&y,&z);
		edg[x].push_back(make_pair(y,z));
		edg[y].push_back(make_pair(x,z));
	}
	dfs_unique(1,0);
	pre_sol(1,n,0);
	scanf("%d",&q);
	for(re i=1;i<=q;i++){
		int x,y;scanf("%d%d",&x,&y);
		//cout<<LCA(x,y)<<endl;
		qus[LCA(x,y)].push_back(QUS(x,y,i));
	}
	memset(vis,false,sizeof(vis));
	get_ans(1,n);
	for(re i=1;i<=q;i++)printf("%d\n",ans[i]);
}

话说最重要的就是vis数组,T飞了

posted @ 2021-08-13 20:27  fengwu2005  阅读(72)  评论(0编辑  收藏  举报