1. 程式人生 > 實用技巧 >XJOI contest 1592

XJOI contest 1592

首先

熱烈慶祝“CSP-S 2020全國開放賽前衝刺模擬訓練題2”圓滿結束!!!

感謝大毒瘤顆粒囊的題目。題目還是很不錯的,部分分設定的合理,各種神仙隨便 AK ,蒟蒻只能爆零。

Problem A

不會,下一個。

暴搜程式碼如下:

#include<bits/stdc++.h>
using namespace std;
struct Num{int a,b;};
Num opt[25];
int l1,r1,l2,r2,cnt;
int dfs(int now,int a,int b,int use)
{
	if(a==0&&b==0&&use%2==0) return 1;
	if(a==0&&b==0) return -1;
	if(now>=20) return 0;
	int tmp;
	tmp=dfs(now+1,a,b,use);
	if(tmp!=0) return tmp;
	tmp=dfs(now+1,a-opt[now].a,b-opt[now].b,use+1);
	if(tmp!=0) return tmp;
	return 0;
}
void solve()
{
	cin>>l1>>r1>>l2>>r2,cnt=0;
	for(int i=l1;i<=r1;++i)
	{
		for(int j=l2;j<=r2;++j)
		cnt+=(dfs(0,i,j,0)>0);
	}
	printf("%d\n",cnt);
}
int main()
{
	opt[0].a=1,opt[0].b=0;
	opt[1].a=-1,opt[1].b=1;
	opt[2].a=0,opt[2].b=-2;
	opt[3].a=2,opt[3].b=2;
	for(int i=4;i<20;++i)
	{
		opt[i].a=opt[i-4].a*(-4);
		opt[i].b=opt[i-4].b*(-4);
	}
	int T;cin>>T;
	while(T--) solve();
}

Problem B

直接列舉矩形寬度,調和級數的和是 \(O(n\log_2 n)\) 級別的。判重直接用 \(\text{hash}\) 即可。但是題目有一點卡常,我的程式碼只能跑一半的分。

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
#define Lint long long
const int N=1e6+5;
const Lint MOD1=19260817;
const Lint MOD2=998244353;
string s;int n;
Lint sum1[N],ksm1[N];
Lint sum2[N],ksm2[N];
set<pair<Lint,Lint> > bag;
inline pair<Lint,Lint> cut(int l,int r)
{
	Lint tmp1=(sum1[r]-sum1[l-1]*ksm1[r-l+1]%MOD1+MOD1)%MOD1;
	Lint tmp2=(sum2[r]-sum2[l-1]*ksm2[r-l+1]%MOD2+MOD2)%MOD2;
	return make_pair(tmp1,tmp2);
}
int solve(int len)
{
	bag.clear();
	if(n%len==0&&n!=len)
	{
		for(int i=1;i+len-1<=n;i+=len)
		{
			pair<Lint,Lint> L=cut(1,i-1),R=cut(i+len,n),tmp;
			tmp.first=(L.first*ksm1[n-i-len+1]%MOD1+R.first)%MOD1;
			tmp.second=(L.second*ksm2[n-i-len+1]%MOD2+R.second)%MOD2;
			bag.insert(tmp);
		}
	}
	Lint rem=n%len;
	for(int i=1;i+rem-1<=n;i+=len)
	{
		pair<Lint,Lint> L=cut(1,i-1),R=cut(i+rem,n),tmp;
		tmp.first=(L.first*ksm1[n-i-rem+1]%MOD1+R.first)%MOD1;
		tmp.second=(L.second*ksm2[n-i-rem+1]%MOD2+R.second)%MOD2;
		bag.insert(tmp);
	}
//	printf("%d\n",(int)bag.size());
	return bag.size();
}
Lint res=0;
int main()
{
	cin>>s,n=s.length(),ksm1[0]=ksm2[0]=1;
	for(int i=1;i<=n;++i) ksm1[i]=ksm1[i-1]*27%MOD1;
	for(int i=0;i<n;++i) sum1[i+1]=(sum1[i]*27+s[i]-'a'+1)%MOD1;
	for(int i=1;i<=n;++i) ksm2[i]=ksm2[i-1]*27%MOD2;
	for(int i=0;i<n;++i) sum2[i+1]=(sum2[i]*27+s[i]-'a'+1)%MOD2;
	for(int i=1;i<=n;++i) res+=solve(i);
	printf("%lld\n",res);
	return 0;
}

Problem C

這道題目感覺還可以,原本應該有機會拿滿分的,但是由於考慮到其他題目的部分分,就沒打(然後發現部分分還沒有這個多)。

就是考慮用 \(f_{i,j,k}\) 表示在第 \(i\) 列搭高度為 \(j\) 的積木時的和,同時 \(k\in {0,1}\) ,表示是否有過高度為 \(h\) 的列。這裡的平方和強行用二項式定理來維護。然後轉移方程易得:

\[f_{i,j,0}=\sum_{k=1}^{h-1} (f_{i-1,k,0}+max(0,j-k)) \]

\[f_{i,j,1}=\sum_{k=1}^h (f_{i-1,k,1}+max(0,j-k)) (j<h) \]

\[f_{i,h,1}=\sum_{k=1}^{h-1} (f_{i-1,k,0}+max(0,j-k))+\sum_{k=1}^h (f_{i-1,k,1}+max(0,j-k)) \]

然後這個東西字首和優化還是比較方便的,然後就可以 \(O(n^2)\) 了。

程式碼如下, \(O(n^3)\) 的做法:

#include<bits/stdc++.h>
using namespace std;
#define Lint long long
const int N=2e2+5;//woshishabi
const Lint MOD=998244353;
int n,m;
Lint way[N][N][2];
Lint f1[N][N][2];
Lint f2[N][N][2];
int main()
{
	cin>>n>>m;
	for(int j=1;j<m;++j)
	f1[1][j][0]=j,f2[1][j][0]=j*j,way[1][j][0]=1;
	f1[1][m][1]=m,f2[1][m][1]=m*m,way[1][m][1]=1;
	for(int i=2;i<=n;++i)
	{
		for(int j=1;j<m;++j)
		{
			for(int k=1;k<m;++k)
			{
				if(j<=k)
				{
					f1[i][j][0]+=f1[i-1][k][0],f1[i][j][0]%=MOD;
					f2[i][j][0]+=f2[i-1][k][0],f2[i][j][0]%=MOD;
					way[i][j][0]+=way[i-1][k][0],way[i][j][0]%=MOD;
					
					f1[i][j][1]+=f1[i-1][k][1],f1[i][j][1]%=MOD;
					f2[i][j][1]+=f2[i-1][k][1],f2[i][j][1]%=MOD;
					way[i][j][1]+=way[i-1][k][1],way[i][j][1]%=MOD;
				}
				else
				{
					f1[i][j][0]+=f1[i-1][k][0]+(j-k)*way[i-1][k][0]%MOD,f1[i][j][0]%=MOD;
					f2[i][j][0]+=f2[i-1][k][0]+2*f1[i-1][k][0]*(j-k)%MOD+way[i-1][k][0]*(j-k)*(j-k)%MOD,f2[i][j][0]%=MOD;
					way[i][j][0]+=way[i-1][k][0],way[i][j][0]%=MOD;
					
					f1[i][j][1]+=f1[i-1][k][1]+(j-k)*way[i-1][k][1]%MOD,f1[i][j][1]%=MOD;
					f2[i][j][1]+=f2[i-1][k][1]+2*f1[i-1][k][1]*(j-k)%MOD+way[i-1][k][1]*(j-k)*(j-k)%MOD,f2[i][j][1]%=MOD;
					way[i][j][1]+=way[i-1][k][1],way[i][j][1]%=MOD;
				}
			}
			f1[i][j][1]+=f1[i-1][m][1],f1[i][j][1]%=MOD;
			f2[i][j][1]+=f2[i-1][m][1],f2[i][j][1]%=MOD;
			way[i][j][1]+=way[i-1][m][1],way[i][j][1]%=MOD;
		}
		for(int k=1;k<=m;++k)
		{
			f1[i][m][1]+=f1[i-1][k][0]+(m-k)*way[i-1][k][0]%MOD,f1[i][m][1]%=MOD;
			f2[i][m][1]+=f2[i-1][k][0]+2*f1[i-1][k][0]*(m-k)%MOD+way[i-1][k][0]*(m-k)*(m-k)%MOD,f2[i][m][1]%=MOD;
			way[i][m][1]+=way[i-1][k][0],way[i][m][1]%=MOD;
			
			f1[i][m][1]+=f1[i-1][k][1]+(m-k)*way[i-1][k][1]%MOD,f1[i][m][1]%=MOD;
			f2[i][m][1]+=f2[i-1][k][1]+2*f1[i-1][k][1]*(m-k)%MOD+way[i-1][k][1]*(m-k)*(m-k)%MOD,f2[i][m][1]%=MOD;
			way[i][m][1]+=way[i-1][k][1],way[i][m][1]%=MOD;
		}
	}
	Lint res=0;
	for(int i=1;i<=m;++i) res+=f2[n][i][1],res%=MOD;
	printf("%lld\n",res);
	return 0;
}

Problem D

不會,下一個。

暴搜如下:

#include<bits/stdc++.h>
using namespace std;
#define Lint long long
const int N=2e2+5,M=1e5+5;
const Lint MOD=998244373;
int n,m,cnt=0;
vector<int> bag[N];
int mp[N][N],deg[N];
int ord[N];bool used[N];
Lint res=0;
void dfs(int now)
{
	if(now>=cnt)
	{
		int hhh=0;
		for(int i=1;i<cnt;++i)
		{
			for(int j=i+1;j<cnt;++j)
			hhh+=(ord[i]>ord[j]);
		}
		Lint sum=1;
		for(int i=1;i<cnt;++i) sum*=mp[i][ord[i]],sum%=MOD;
		res+=MOD+pow(-1,hhh)*sum,res%=MOD;
		return ;
	}
	for(int i=1;i<cnt;++i)
	{
		if(used[i]) continue;
		used[i]=true;
		ord[now]=i;
		dfs(now+1);
		used[i]=false;
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1,x;i<=n;++i)
	{
		scanf("%d",&x);
		for(int j=1;j<=x;++j)
		bag[i].push_back(++cnt);
	}
	for(int i=1,u,v;i<=m;++i)
	{
		scanf("%d%d",&u,&v);
		for(int c=0;c<(int)bag[u].size();++c)
		{
			for(int d=0;d<(int)bag[v].size();++d)
			{
				if(bag[u][c]==bag[v][d]) continue;
				mp[bag[u][c]][bag[v][d]]++;
				mp[bag[v][d]][bag[u][c]]++;
				deg[bag[u][c]]++;
				deg[bag[v][d]]++;
			}
		}
	}
	for(int i=1;i<=cnt;++i)
	{
		for(int j=1;j<=cnt;++j)
		{
			if(i!=j) mp[i][j]=-mp[i][j];
			else mp[i][j]=deg[i];
		}
	}
	for(int i=1;i<=cnt;++i)
	{
		for(int j=1;j<=cnt;++j)
		mp[i+cnt-1][j]=mp[i][j];
	}
	dfs(1);
	printf("%lld\n",res);
}