csp-j 2025

csp-j 2025


CSP-J 2025考完后只是看了一下,一直没有做,这两天有时间就做了一下。
四个题目,拼数、座位、异或和、多边形。前两个比较简单,送分题。后两个还不错。
异或和用到了异或和的性质,做了一个简单的DP。
f[i]:前i个数可以最多可以选出的区间数。根据第i个数是否在最后一个区间里可以得出

\[f[i]=max(f[i-1],f[j]+1)(sz[j+1]\verb|^|sz[j+2]\verb|^|……\verb|^|sz[i]==k) \]

当然上面的条件可以用前缀和优化处理,就得到了\(sz[i]\verb|^| sz[j]==k\)(这里的sz[x]是上面原sz数组的第0-x个的前缀和),变形就可以得到\(sz[i] \verb|^| k==sz[j]\) ,这样只需要判断sz[j]是否存在,这需要打标记。从公式很容易看出f[i]数组是单调递增的,f[i]只需要用和f[i-1]一样大的值进行更新。


#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
long long sz[maxn],f[maxn];
int bz[(1<<20)+10];
int n;
long long k;
int main()
{
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;++i)
	{
		scanf("%lld",&sz[i]);
		sz[i]^=sz[i-1];
	}
	bz[0]=1;
	int l=0;
	for(int i=1;i<=n;++i)
	{
		int tp=sz[i]^k;
		if(bz[tp])
		{
			f[i]=f[i-1]+1;
			bz[sz[i]]+=1;
			while(l<i)
			{
				bz[sz[l]]-=1;
				++l;
			}
		}
		else 
		{
			bz[sz[i]]+=1;
			f[i]=f[i-1];
		}
	}
	cout<<f[n]<<endl;
	return 0;
}

第四个题目,多边形。同样是DP。里面用排列组合,用杨辉三角预处理就可以了。

//f[i][j]:前i个数组成的和大于j的方案数
//f[i][j]=f[i-1][j]+f[i-1][j-a[i]]
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e3+10;
const int mod=998244353;
int n;
int sz[maxn];
long long f[maxn][maxn],yh[maxn][maxn],yhh[maxn];

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n+1;++i)yh[i][1]=yh[i][i]=1;
	for(int i=3;i<=n+1;++i)
		for(int j=2;j<i;++j)
			yh[i][j]=(yh[i-1][j-1]+yh[i-1][j])%mod;
	for(int i=1;i<=n+1;++i)
		for(int j=1;j<=i;++j)yhh[i]=(yhh[i]+yh[i][j])%mod;
	for(int i=1;i<=n;++i)scanf("%d",sz+i);
	sort(sz+1,sz+n+1);
	for(int i=0;i<sz[1];++i)f[1][i]=1;
	for(int i=2;i<n;++i)
		for(int j=0;j<=sz[n];++j)
			f[i][j]=(f[i-1][j]+(j-sz[i]>=0?f[i-1][j-sz[i]]:yhh[i]))%mod;
	long long ans=0;
	for(int i=3;i<=n;++i)ans=(ans+f[i-1][sz[i]])%mod;
	cout<<ans<<endl;
	return 0;
}

posted on 2026-09-11 13:35  gryzy  阅读(31)  评论(0)    收藏  举报

导航