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;
}
浙公网安备 33010602011771号