多校A層衝刺NOIP2024模擬賽03

zhengchenxi發表於2024-10-09

T1.colorfu

正難則反,直接列舉橫行,列舉右邊界,如果相同,則會對後面以及它本身統計產生 \(1\) 的貢獻,我們直接開個桶統計一下。

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=1000+107;
int n,m;
int a[N][N],cnt[N*N];
int sum;

int read()
{
	int f=1,s=0;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){s=(s<<1)+(s<<3)+(c^48);c=getchar();}
	return f*s;
}

signed main()
{
	freopen("colorful.in","r",stdin);
	freopen("colorful.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			a[i][j]=read();
		}
	}
	sum=n*(n+1)*m*(m+1)/4;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=i;j<=n;j++)
		{
			for(int k=1;k<=m;k++)
			{
				if(a[i][k]==a[j][k])
				{
					++cnt[a[i][k]];
					ans+=cnt[a[i][k]];
				}
			}
			for(int k=1;k<=m;k++) cnt[a[i][k]]=0;
		}
	}
	printf("%lld",sum-ans);
}

T2.travel

雙指標統計,不難發現值域很大,操作很少,我們發現一段區間更新後這一段時間的值不會立刻再發生改變,類似於莫隊的移動邊界到查詢點的操作,我們差分處理一下,然後排序,直接模擬移動即可。

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=4e6+107;
const int mod=1e9+7;
int n,m,s,t;


struct lmy
{
	int x,pos,val;
}a[N];
bool comp(lmy a,lmy b){return a.pos==b.pos?a.val<b.val:a.pos<b.pos;}

int p[N],g[N];

int read()
{
	int f=1,s=0;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){s=(s<<1)+(s<<3)+(c^48);c=getchar();}
	return f*s;
}

int qpow(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=ans*a%mod;
		a=a*a%mod;
		b=b>>1;
	}
	return ans;
}


signed main()
{
	freopen("travel.in","r",stdin);
	freopen("travel.out","w",stdout);
	n=read(),m=read(),s=read(),t=read();
	p[m*2+1]=s,p[m*2+2]=t+1;
	for(int i=1;i<=m;i++)
	{
		int x=read(),l=read(),r=read();
		p[i]=l,p[i+m]=r+1;
		a[i]={x,l,1},a[i+m]={x,r+1,-1};
	}
	sort(p+1,p+1+2*m+2),sort(a+1,a+1+2*m,comp);
//	int len=unique(p+1,p+1+2*m+2)-(p+1);
	int j=0; int ans=1; int snum=n;
	for(int i=1;i<m*2+2;i++)
	{
		while(j<m*2&&a[j+1].pos<=p[i])
		{
			j++;
			int x=a[j].x;
			int d=a[j].val;
			if(g[x]>0&&g[x]+d<=0) snum++;
			if(g[x]<=0&&g[x]+d>0) snum--;
			g[x]+=d;
		}
		ans=ans*qpow(snum,p[i+1]-p[i])%mod;
	}
	printf("%lld",ans);
	
}

T3.segment

題解挺清楚的

T4.experiment

計數DP轉機率DP,首先將 \(i\)\(b_i\) 建一條邊,很顯然 \(n\) 一定處於一顆基環樹中,我們直接 \(dfs\) 找出環上最小的節點,接著列舉斷邊還是不斷邊,跑DP轉移即可。我們設 \(f_i\) 表示 \(i\) 節點為貓的機率。 \(u\) 為當前節點, \(v\) 為子節點。

轉移:

\(f_v=f_u*f_v\)

\(f_v=f_u*(1-f_v)\)

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=3e4+107;
const int mod=1e9+7;
const int inv2=500000004;
int n,root;
int b[N],vis[N];
char s[N];
int f[N];

int read()
{
	int f=1,s=0;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){s=(s<<1)+(s<<3)+(c^48);c=getchar();}
	return f*s;
}

int qpow(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=ans*a%mod;
		a=a*a%mod;
		b=b>>1;
	}
	return ans;
}

int fa[N];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy) fa[fx]=fy;
}

int dfs1(int x)
{
	vis[x]=1;
	int y=b[x];
	return (vis[y]==1)?x:dfs1(y);
}

void dfs(int x,int &root)
{
	root=min(root,x);
	vis[x]=1;
	int y=b[x];
	if(vis[y]==0) dfs(y,root);
}

signed main()
{
	freopen("experiment.in","r",stdin);
	freopen("experiment.out","w",stdout);
	int t=read();
	while(t--)
	{
		memset(vis,0,sizeof vis);
		int ans=0,sum=0;
		n=read();
		for(int i=1;i<=n;i++) fa[i]=i;
		
		for(int i=1;i<=n;i++) scanf(" %c",&s[i]);
		for(int i=1;i<=n;i++) 
		{
			b[i]=read();
			merge(i,b[i]);
			sum+=(s[i]=='?');
		}
		for(int i=1;i<=n;i++) 
		{
			if(find(i)==fa[n])
			{
				root=dfs1(i);
				break;
			}
		}
		memset(vis,0,sizeof vis);
		dfs(root,root);
		int num=0;
		for(int j=0;j<=1;j++)
		{
			for(int k=0;k<=1;k++)
			{
				for(int i=1;i<=n;i++) 
				{
					if(s[i]=='C') f[i]=1;
					if(s[i]=='.') f[i]=0;
					if(s[i]=='?') f[i]=inv2;
				}
				for(int i=1;i<=n;i++)
				{
					int y=b[i];
					if(i==root)
					{
						if(j==1) 
						{
							if(k==1) num=f[i]*f[y]%mod;
							if(k==0) num=f[i]*(1-f[y]+mod)%mod;
						}
						if(j==0)
						{
							if(k==1) num=(1-f[i]+mod)%mod*f[y]%mod;
							if(k==0) num=(1-f[i]+mod)%mod*(1-f[y]+mod)%mod;
						}
						f[i]=j;
						f[y]=k;
					}
					int tmp=f[i];
					f[i]=tmp*f[y]%mod;
					f[y]=(f[y]+((1-f[y]+mod)%mod)*tmp%mod)%mod;
				}
				ans=(ans+num*f[n]%mod)%mod;
			}
		}
		printf("%lld\n",ans*qpow(2,sum)%mod);
	}
}