noip模拟28[我要玩符卡|我有超能力]

noip模拟28 solutions

怎么说呢这个分数并不在我的意料范围之内

哈哈哈其实还不错,就是对于期望这一块,我理解的还是不够好

T1 遗忘之祭仪

说白了就是一个\(O(n^4)\)的算法,直接去跑一跑,过程中剪剪枝,然后复杂度就无限接近\(O(n2)\)

但是这个出题人非常气人,你要特判一下符卡中啥也没有的情况,我就因为这个

浮点数例外

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1005;
const int inf=0x3f3f3f3f;
int n,m,nm[N][N],sn;
int a,b,ab[N][N],sa,xf=inf,xs,yf=inf,ys;
int sum;
signed main(){
	int T;scanf("%d",&T);
	while(T--){
		//cout<<T<<endl;
		xf=inf;yf=inf;xs=0;ys=0;
		sn=0;sa=0;
		memset(nm,0,sizeof(nm));
		memset(ab,0,sizeof(ab));
		scanf("%d%d%d%d",&n,&m,&a,&b);
		for(re i=1;i<=n;i++){
			char x[N];
			scanf("%s",x+1);
			for(re j=1;j<=m;j++){
				if(x[j]=='x'){
					nm[i][j]=1,sn++;
				}
			}
		}
		for(re i=1;i<=a;i++){
			char x[N];
			scanf("%s",x+1);
			for(re j=1;j<=b;j++){
				if(x[j]=='x'){
					ab[i][j]=1,sa++;
					xf=min(xf,i);xs=i;
					yf=min(yf,j);
					ys=max(ys,j);
				}
			}
		}
		a=xs-xf+1;b=ys-yf+1;
		if(n<a||m<b||a==0||b==0||sa==0){
			printf("No\n");
			continue;
		}
		for(re i=1;i<=a;i++)
			for(re j=1;j<=b;j++)
				ab[i][j]=ab[i+xf-1][j+yf-1];
		if(sn%sa){
			//cout<<"sb"<<endl;
			printf("No\n");
			continue;
		}
		for(re i=1;i<=n-a+1;i++){
			for(re j=1;j<=m-b+1;j++){
				int flag=0;
				for(re x=1;x<=a;x++){
					for(re y=1;y<=b;y++){
						if(nm[i+x-1][j+y-1]!=ab[x][y]&&ab[x][y]){
							flag=1;break;
						}
					}
					if(flag)break;
				}
				if(flag)continue;
				//sum++;
				for(re x=1;x<=a;x++){
					for(re y=1;y<=b;y++){
						if(ab[x][y])nm[i+x-1][j+y-1]=0;
					}
				}
			}
		}
		int flag=0;
		for(re i=1;i<=n;i++)
			for(re j=1;j<=m;j++)
				if(nm[i][j])flag=1;
		if(flag)printf("No\n");
		else printf("Yes\n");
	}
}

T2 客星璀璨之夜

我也知道这是那个最最最经典的小球进洞的题

但是吧,我就是不会,说白了就是傻

仔细想一想的话,你会发现,在这些星星们不断减少的过程中,其实每条路径的长度不变

这其实就可以开始转移没条路径的经过次数的期望了

直接从下面转移就好了,因为你的边是在一点一点的减少的哈哈哈,

就是代码啦,直接手摸一下数据就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=3005;
const ll mod=998244353;
ll n,m,a[N*2];
ll f[N][N*2];
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;
}
ll ans,jc=1;
signed main(){
	scanf("%lld",&n);m=2*n+1;
	for(re i=1;i<=m;i++)scanf("%lld",&a[i]);
	for(re i=1;i<=n;i++){
		ll fi=ksm(i,mod-2),se=ksm(i*2,mod-2);
		for(re j=2;j<=2*i+1;j++){
			ll num=(i*2+1-j)/2;
			if(j&1)f[i][j]=(f[i-1][j]*num%mod*fi%mod+f[i-1][j-1]*se%mod+f[i-1][j-2]*((i-num)*2-1)%mod*se%mod+se)%mod;
			else f[i][j]=(f[i-1][j]*(num*2+1)%mod*se%mod+f[i-1][j-1]*se%mod+f[i-1][j-2]*((i-num-1))%mod*fi%mod+se)%mod;
		}
	}
	for(re i=2;i<=m;i++){
		ans=(ans+(a[i]-a[i-1])*f[n][i]%mod)%mod;
	}
	printf("%lld",ans);
}

T3 割海成路之日

所以这个题的并查集用的极其的妙

首先要维护两个并查集这事,肯定是个人都能想出来

所以我们直接维护好那些要经过3边的点的个数,在每一次更改的时候在增增减减

直接上代码

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define pa pair<int,int>
#define mpa(x,y) make_pair(x,y)
#define gc if(++ip==ie)fread(ip=buf,1,SZ,stdin)
const int SZ=1<<19;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int read(){
	int x;scanf("%d",&x);
	return x;
    /*gc;while(*ip<'-')gc;
    bool f=*ip=='-';if(f)gc;
    int x=*ip&15;gc;
    while(*ip>'-'){x*=10;x+=*ip&15;gc;}
    return f?-x:x;*/
}
const int N=3e5+5;
int n,m;
struct DJS{
	int fa[N],siz[N];
	DJS(){for(re i=1;i<=n;i++)fa[i]=i,siz[i]=1;}
	int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
	void add(int x,int y){
		int fx=find(x);
		int fy=find(y);
		if(fx!=fy){
			fa[fx]=fy;
			siz[fy]+=siz[fx];
		}
		return ;
	}
};
int to[N*2],nxt[N*2],val[N*2],head[N],rp;
void add_edg(int x,int y,int z){
	to[++rp]=y;
	val[rp]=z;
	nxt[rp]=head[x];
	head[x]=rp;
}
bool vis[N];
int fa[N],w[N];
void dfs(int x,int f,int v){
	w[x]=v;fa[x]=f;
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==f)continue;
		dfs(y,x,val[i]);
	}
}
int f[N];
signed main(){
	//scanf("%d%d",&n,&m);
	n=read();m=read();
	DJS a,b;
	for(re i=1,x,y,z;i<n;i++){
		//scanf("%d%d%d",&x,&y,&z);
		x=read();y=read();z=read();
		add_edg(x,y,z);add_edg(y,x,z);
	}
	//cout<<"finish edge"<<endl;
	dfs(1,0,0);
	//cout<<"finish dfs"<<endl;
	for(re i=1;i<=n;i++){
		//cout<<w[i]<<endl;
		if(w[i]==1)a.add(i,fa[i]);
		if(w[i]!=3)b.add(i,fa[i]);
	}
	for(re i=1;i<=n;i++){
		if(w[i]==3)f[a.find(fa[i])]+=b.siz[i];
	}
	//for(re i=1;i<=n;i++)cout<<f[i]<<endl;
	for(re i=1,x,y,s,t;i<=m;i++){
		//cout<<i<<endl;
		scanf("%d%d%d%d",&x,&y,&s,&t);
		if(fa[x]==y)swap(x,y);
		if(w[y]==3){
			f[a.find(x)]-=b.siz[y];
			f[a.find(fa[b.find(x)])]+=b.siz[y];
			b.add(y,x);
		}
		if(w[y]==2){
			f[a.find(x)]+=f[y];
			a.add(y,x);
		}
		if(w[y]!=1)w[y]--;
		int flag=0,ans=0;
		if(b.find(s)==b.find(t))flag=1;
		if(a.find(s)==a.find(fa[b.find(t)]))flag=1;
		if(b.find(fa[a.find(s)])==b.find(t))flag=1;
		if(flag)printf("1 ");
		else printf("0 ");
		ans=b.siz[b.find(s)]+f[a.find(s)];
		if(w[a.find(s)]==3)ans+=b.siz[b.find(fa[a.find(s)])];
		printf("%d\n",ans);
	}
}
posted @ 2021-08-02 15:27  fengwu2005  阅读(76)  评论(0编辑  收藏  举报