2024.7.31模拟赛12

模拟赛

打的最好的一场?

T1

题目描述

发现 \(z \in [0,999]\),果断选择枚举 \(z\)。然后枚举 \(z\) 的拆分,算出现次数统计。

注意我们只需要记录两两互质的情况,不互质的会在统计出现次数时算到。

最后由于求的是区间,小容斥一下。

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int mod  = 1e9+7;
LL a,b,c,d,ans;
LL work(LL n,LL m)
{
	LL res=0;
	for(int i=1;i<=min(n+m,999ll);i++)
	{
		for(int j=1;j<i;j++)
		{
			if(__gcd(i-j,j)!=1) continue;
			LL tmp=min(n/(i-j),m/j);
			res=(res+tmp*i)%mod;
		}
	}
	return res;
}
int main()
{
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
	ans=((work(b,d)-(work(b,c-1)+work(a-1,d))%mod+mod)+work(a-1,c-1))%mod;
	printf("%lld\n",ans);
	return 0;
}

T2 Shuffle Permutation

无论行列如何交换,两个在同一行的数还在同一行,在同一列的还在同一列。

也就是行的变换与列的变换完全是独立的,我们可以单独算方案再乘起来。

然后先考虑列交换,发现如果 \((a,b),(b,c)\) 分别可以交换,那 \((a,b,c)\) 之间显然可以互换,也就是交换具有传递性。

所以可以用并查集维护(其实就是连通性)。最后对每个连通块内统计一下答案就行了。

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 55,mod = 998244353;
int n,k;
int a[N][N],sz[N];
int fa[N];
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
LL ans=1,p[N];
int main()
{
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	scanf("%d%d",&n,&k);
	p[1]=1; for(int i=2;i<=n;i++) p[i]=p[i-1]*i%mod;
	for(int i=1;i<=n;i++) fa[i]=i,sz[i]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			scanf("%d",&a[i][j]);
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			bool fl=1;
			for(int h=1;h<=n;h++)
			{
				if(a[i][h]+a[j][h]>k) 
				{
					fl=0;break;
				}
			}
			if(fl)
			{
				
				int fx=find(i),fy=find(j);
				if(fx==fy) continue;
				sz[fx]+=sz[fy]; sz[fy]=0;
				fa[fy]=fx;
			}	
		}
	}
	for(int i=1;i<=n;i++) if(sz[i]>1) ans=(ans*p[sz[i]])%mod;
	for(int i=1;i<=n;i++) fa[i]=i,sz[i]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			bool fl=1;
			for(int h=1;h<=n;h++)
			{
				if(a[h][i]+a[h][j]>k) 
				{
					fl=0;break;
				}
			}
			if(fl)
			{
				int fx=find(i),fy=find(j);
				if(fx==fy) continue;
				sz[fx]+=sz[fy]; sz[fy]=0;
				fa[fy]=fx;
			}	
		}
	}
	for(int i=1;i<=n;i++) if(sz[i]>1) ans=(ans*p[sz[i]])%mod;
	printf("%lld\n",ans);
	return 0;
}

T3 亚瑟王

遇见期望 dp,先想单独算每一个的贡献,然后加起来。

既然单独计算每张牌被选的概率,那我们假设还有 \(j\) 次选牌的机会,那不选这张牌的概率是 \((1-p_i)^j\),选这张的概率就是 \(1-(1-p_i)^j\)

然后枚举 \(i,j\)(注意期望 dp 倒叙枚举),就做完了。(现在看这么简单?!)

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define scan __builtin_scanf
#define print __builtin_printf
#define doubl long double
const int N = 300;
int t,n,r;
doubl f[N][N],p[N],d[N];
doubl qpow(doubl a,int b)
{
	doubl res=1.0;
	while(b)
	{
		if(b&1) res=res*a;
		a=a*a; b>>=1;
	}
	return res;
}
int main()
{
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	scan("%d",&t);
	while(t--)
	{
		memset(f,0,sizeof(f));
		scan("%d%d",&n,&r);
		for(int i=1;i<=n;i++) scan("%Lf%Lf",&p[i],&d[i]);
		for(int i=n;i>=1;i--)
		{
			for(int j=1;j<=r;j++)
			{
				doubl tmp=qpow(1.0-p[i],j);
				f[i][j]=f[i+1][j]*tmp+(f[i+1][j-1]+d[i])*(1.0-tmp);
			}
		}
		print("%.10Lf\n",f[1][r]);
	}
	return 0;
}

T4 Serega and Fun

vector 立大功。

我的分块复杂度假的,没有维护块长,假如每次都将最后一个数放进第一个块,最后卡到 \(n^2\) 的。

正解就是把 vector,换成 deque。每次修改操作都将块多出的一个放到下一个块里。

false code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5+1,S = 1000;
int n,q,a[N],bl,tot,ans,cnt[105][N];
vector<int> v[105];

void mdf(int l,int r)
{
	int tmp1=1,tmp2=1;
	while(tmp1<tot&&v[tmp1].size()<l)
	{
		l-=v[tmp1].size(); r-=v[tmp1].size();
		tmp1++,tmp2++;
	}
	while(tmp2<tot&&v[tmp2].size()<r)
	{
		r-=v[tmp2].size(); tmp2++;
	}
	int t=v[tmp2][r-1];
	cnt[tmp2][t]--; cnt[tmp1][t]++;
	v[tmp2].erase(v[tmp2].begin()+r-1);
	v[tmp1].insert(v[tmp1].begin()+l-1,t);
}
int que(int l,int r,int k)
{
	int t1=1,res=0;
	while(t1<tot&&v[t1].size()<l) l-=v[t1].size(),r-=v[t1].size(),t1++;
	if(r<=v[t1].size())
	{
		for(int i=l-1;i<=r-1;i++) 
		{
			if(v[t1][i]==k) res++;
		}
	}
	else
	{
		for(int i=l-1;i<v[t1].size();i++) if(v[t1][i]==k) res++;
		r-=v[t1].size(); t1++;
		while(t1<tot&&v[t1].size()<r) r-=v[t1].size(),res+=cnt[t1][k],t1++;
		for(int i=0;i<r;i++) if(v[t1][i]==k) res++;
	}
	return res;
}
int main()
{
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	scanf("%d",&n); tot=1;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		v[tot].push_back(a[i]);
		cnt[tot][a[i]]++;
		if(v[tot].size()>=S) tot++;
	}
	scanf("%d",&q);
	int ans=0;
	while(q--)
	{
		int c; scanf("%d",&c);
		if(c==1)
		{
			int x,y; scanf("%d%d",&x,&y);
			x=((x+ans-1)%n)+1; y=((y+ans-1)%n)+1;
			if(x>y) swap(x,y);
			mdf(x,y);
		}
		else 
		{
			int x,y,z; scanf("%d%d%d",&x,&y,&z);
			x=((x+ans-1)%n)+1; y=((y+ans-1)%n)+1; z=((z+ans-1)%n)+1;
			if(x>y) swap(x,y);
			ans=que(x,y,z);
			printf("%d\n",ans);
		}
	}
	return 0;
}
posted @ 2024-08-12 20:54  ppllxx_9G  阅读(14)  评论(0编辑  收藏  举报