5.21模拟赛

Day1

个人认为可能是最难的一天。
第一题是字符串,因为前段时间一直在加训 SAM,感觉SAM至少能做一些部分分出来,所以就可能思考了比较久的 T1,但是对于T1字典序最小的要求我只有一个时间复杂度比较劣的二分hash做法而且写起来非常的复杂,就留到了最后写。对于T2一开始是完全没有思路,在做完了简单好打的部分分后,也在思考能不能拓展,发现一的情况是非常的特殊,还有一档暴力枚举的部分,细节比较多没什么价值就没有写。对于 T3 还是思考到了比较浅显的地方,但是对于这个做法不会优化,对于部分分互质给出的提示也没有深入理解,导致只能写低分暴力。

T1

下午发现 T1 是 SA 并且比较困难,在wyh讲第二遍时听懂了但是没有去实现。主要思路是首先枚举 \(|root(s)|=x\) ,将 \(x,2x,3x\) 设为关键点,显然 \(|root|=x\) 的字符串一定会经过其中一个点。对于每两个点中间(不一定刚好是循环节,可能不是完整周期)的一段统计左边、右边最远能到哪(用LCP,LCS去刻画),字典序最小也用LCP比较快速得到。 第二问扫描线。

T2

T2是需要一个巧妙的图论建模(可能这种限制比较神秘的条件都可以尝试用图来刻画)转化为选不共段点的线段的边权最大值之和。考虑对于 \(i+j\) 是奇数的格左上格点向右下格点连边,否则就左下格点向右上连边,边权就是值。容易发现任意两个不能同时选的格子,代表边一定有一个公共格点。然后就根据网格图转为二分图,偶数行和奇数行建图跑费用流即可。

#include <bits/stdc++.h>
using namespace	std;
#define ll long long 
#define INF 4557430888798830399
int n,m,s,t,tot=1,hd[500010],nxt[500010],go[500010],pre[500010],cc[500010],jz[500010],flow[500010];
ll ans,ansjz,dis[500010];
bool vis[500010],b[1002][1002];
queue<int> q;
inline void add(int x,int y,ll z,ll c)
{
	nxt[++tot]=hd[x];go[tot]=y;cc[tot]=c;jz[tot]=z;hd[x]=tot;
	nxt[++tot]=hd[y];go[tot]=x;cc[tot]=-c;jz[tot]=0;hd[y]=tot;
	return;
}
inline bool spfa()
{
	memset(dis,0x3f,sizeof(dis));
	queue<int> q;
	for(int i=1;i<=n;i++)vis[i]=0;
	vis[s]=1;
	dis[s]=0;
	q.push(s);
	flow[s]=INF;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		vis[u]=0;
		for(int i=hd[u];i;i=nxt[i]) 
		{
			if(jz[i]==0)continue;
			int v=go[i];
			if(dis[v]>dis[u]+cc[i])
			{
				dis[v]=dis[u]+cc[i];
				flow[v]=min(flow[u],jz[i]);
				pre[v]=i;
				if(!vis[v])vis[v]=1,q.push(v);
			}	
		}
	}
	if(dis[t]==INF)return 0;
	return 1;
}
inline void update()
{
	int k=t;
	while(k!=s)
	{
		int las=pre[k];
		jz[las]-=flow[t];
		jz[las^1]+=flow[t];
		k=go[las^1];
	}
	ans+=flow[t];
	ansjz+=dis[t]*flow[t];
	return ;
}
int bh(int x,int y){return (x-1)*(m+1)+y;}
void fenjie(int &x,int &y,int z){y=(z%(m+1)?z%(m+1):m+1);x=(z-y)/(m+1)+1;}
signed main()
{
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	cin>>n>>m;
	s=0,t=(n+1)*(m+1)+1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			int x;cin>>x;
			if((i+j)&1)
			{
				if(i&1)add(bh(i,j),bh(i+1,j+1),1,-x);
				else add(bh(i+1,j+1),bh(i,j),1,-x);
			}
			else
			{
				if(i&1)	add(bh(i,j+1),bh(i+1,j),1,-x);
				else add(bh(i+1,j),bh(i,j+1),1,-x);
			} 
		}
	}
	for(int i=1;i<=n+1;i++)
	{
		for(int j=1;j<=m+1;j++)
		{
			if(i&1)add(s,bh(i,j),1,0),add(bh(i,j),t,1,0);
			else add(bh(i,j),t,1,0);
		}
	}
	while(spfa())update();
	cout<<-1*ansjz<<'\n'; 
	for(int i=1;i<=n+1;i+=2)
	{
		for(int j=1;j<=m+1;j++)
		{
			int id=bh(i,j);
			for(int x=hd[id];x;x=nxt[x])
			{
				int v=go[x];
				if(v==s||v==t||jz[x])continue;
				int wzx,wzy;fenjie(wzx,wzy,v);
				if(wzx<i)
				{
					if(wzy<j)b[i-1][j-1]=1;
					else b[i-1][j]=1; 
				}
				else
				{
					if(wzy<j)b[i][j-1]=1;
					else b[i][j]=1; 
				}
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)cout<<b[i][j]<<" ";
		cout<<'\n';
	}
	return 0; 
} 

T3

T3 先处理互质(只要互质那么每一对组合都会出现一次,直接求和相乘即可)。对于不互质的情况,我们考虑日期对一个常数 \(K\) 取模,对于所有取模相同的日期一起处理,那么商店的周期随之改变,只要新周期互质,就可以像互质一样处理。对于 \(K\) 的具体值,我们先考虑对于周期相同和周期成倍数的预处理到一起,这样只剩下区间 \([51,100]\) 长度的周期,然后写一个暴力枚举 \(K\) 的值就可以得出 \(K=2520\) 时这些值取模后互质。最后再将答案加起来即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e3+10,mod=998244353,M=100;
int n,ans,T=2520;
bool vis[N];
vector<int> a[M+5],b[M+5];
int gcd(int x,int y)
{
	if(y==0)return x;
	else return gcd(y,x%y);
 } 
int lcm(int x,int y){return x*y/gcd(x,y); }
int ksm(int x,int y)
{
	int res=1;
	while(y)
	{
		if(y&1) res=res*x%mod;
		y>>=1;
		x=x*x%mod; 
	}
	return res;
}
bool cmp(const vector<int> &a,const vector<int> &b)
{
	return a.size()<b.size();
}
void solve()
{
	cin>>n;ans=0;
	for(int i=1;i<=M;i++)
	{
		a[i].resize(i);
		for(int j=0;j<i;j++)a[i][j]=1;
	}//对每种长度初始化 
	for(int i=1;i<=n;i++)
	{
		int l;cin>>l;
		for(int j=0;j<l;j++)
		{
			int z;cin>>z;
			a[l][j]=a[l][j]*((1-z+mod)%mod)%mod;
		}
	}//已经对所有相同长度处理到一起。
	for(int t=0;t<T;t++)//枚举取模后的余数 
	{
		//cout<<t<<'\n'; 
		for(int i=1;i<=M;i++)
		{
			vis[i]=0; 
			int xl=i/gcd(i,T); //cout<<i<<" "<<xl<<'\n';
			b[i].resize(xl);
			for(int j=0;j<xl;j++)b[i][j]=a[i][(t+j*T)%i]; 
		} 
		sort(b+1,b+M+1,cmp);//按大小排序 
		
		for(int i=1;i<=M;i++)
		{
			for(int j=i+1;j<=M;j++)
			{
				if(b[j].size()%b[i].size()==0)
				{
					for(int k=0;k<b[j].size();k++)b[j][k]=b[j][k]*b[i][k%b[i].size()]%mod;
					vis[i]=1;
					break;
				}
			} 
		} 
		int res=1;
		for(int i=1;i<=M;i++)
		{
			if(vis[i])continue;
			res=res*(accumulate(b[i].begin(),b[i].end(),0ll)%mod)%mod*ksm(b[i].size(),mod-2)%mod;
		}
		ans=(ans+res)%mod;
	} 
	cout<<(1-ans*ksm(T,mod-2)%mod+mod)%mod<<'\n';
}
signed main()
{
	freopen("popsicle.in","r",stdin);
	freopen("popsicle.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int t;cin>>t;
	while(t--)solve();
	return 0;
}
posted @ 2025-05-26 15:47  exCat  阅读(18)  评论(1)    收藏  举报