多校A层冲刺NOIP2024模拟赛03

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);
	}
}
posted @ 2024-10-09 19:53  zhengchenxi  阅读(14)  评论(0编辑  收藏  举报