C0427 【20251025】2025 CSP-J 联测5 总结

总结

T1,T2,T3

考场上很快就打出了正解,没什么问题。

T4

考场上打了一个部分分。没什么问题。

题解

T1

照题意模拟即可。

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=3000+5;
char a[maxn][maxn];
set<string> s;
signed main()
{
	// freopen("painting.in","r",stdin);
	// freopen("painting.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n,m;cin>>n>>m;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
	for(int i=1;i<=n;i+=3)
	{
		for(int j=1;j<=m;j+=3)
		{
			string str="";
			for(int k=i;k<=i+2;k++) for(int l=j;l<=j+2;l++) str=str+a[k][l];
			s.insert(str);
		}
	}
	cout<<s.size();
	return 0;
}

T2

注意到 \(a\) 的值特别小,所以我们直接拿个桶,把每一个值给他塞进去。然后逐个判断即可。

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=1e5+5;
int a[maxn][55];
signed main()
{
	// freopen("instrument.in","r",stdin);
	// freopen("instrument.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n;cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=50;j++) a[i][j]=a[i-1][j];
		int x;cin>>x;
		a[i][x]++;
	}
	int m;cin>>m;
	while(m--)
	{
		int l,r,ans=0;cin>>l>>r;
		for(int i=0;i<=50;i++)
		{
			if(a[r][i]-a[l-1][i])
			{
				int sum=a[r][i]-a[l-1][i];
				while(a[r][i+1]-a[l-1][i+1]) i++,sum+=a[r][i]-a[l-1][i];
				ans=sum;
				break;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

T3

如果有两个字符串,它们的关系很好,那么我同时对它们删除同样个数的开头或者结尾。他们一定关系还是很好的。

而如果说既要删开头,又要删结尾,显然是不那么好判断的。所以我们可以考虑固定结尾。只删开头。

那么设 \(f_{i,j}\) 表示当前一个串以 \(i\) 结尾,另外一个串以 \(j\) 结尾,那么它们同时最长能够关系很好的串有多长。

那么我们只需要枚举一下 \(i\)\(j\) 之间的距离,然后再枚举一下 \(i\)。然后我们看一下最长到哪儿合法即可。

那么对于答案的话我们在此可以让 \(f_{i,j}\)\(i\)\(j\) 之间的距离比个最小值。

那么接下来的话我们会发现。当前切割的位置一定在两者之间。如果说都没有包含到好,最长能够关系很好的两个串,那么它的总的贡献就会贡献。最长的能够关系很好的两个串的长度。否则就是把最长的关系很好的这两个长度减去我切割到的部分即可。

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=3e3+5;
int f[maxn][maxn],ans[maxn];
char a[maxn];
signed main()
{
	// freopen("difference.in","r",stdin);
	// freopen("difference.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n,k;cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int len=1;len<=n;len++)
	{
		int sum=0,l=1;
		for(int i=1,j=i+len;j<=n;i++,j++)
		{
			sum+=(a[i]!=a[j]);
			while(sum>k) sum-=(a[l]!=a[l+len]),l++;
			f[i][j]=min(len,i-l+1);
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
		{
			ans[i]+=f[i][j];
			ans[i+1]-=f[i][j];
			ans[j-f[i][j]+1]--;
			ans[j+1]++;
		}
	for(int i=1;i<=n;i++) ans[i]+=ans[i-1];
	for(int i=1;i<=n;i++) ans[i]+=ans[i-1];
	for(int i=1;i<n;i++) cout<<ans[i]<<endl;
	return 0;
}

T4

考虑差贡献。

如果说当前只有一个值那么我们就将他的这个值去除以 \(k\),然后再向下取整。

而对于多个值,我们可以设 \(dp_{i,j}\)。表示,前面这么多个刚好可以凑出来模 \(k\) 等于 \(j\) 的值的方案数。

每次新来一个值。我看如果说它当前加上磨出来的这个值超过了 \(k\)。那么答案就可以加。否则的话就只能累积到方案数。

最后把答案说出即可。

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=5000+5;
int a[maxn],g[maxn],dp[maxn][maxn];
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n,k,mod,ans=0;cin>>n>>k>>mod;
	g[0]=1;
	for(int i=1;i<=n;i++) g[i]=g[i-1]*2%mod;
	for(int i=1;i<=n;i++) cin>>a[i],ans=(ans+a[i]/k*g[n-1]%mod)%mod,a[i]%=k;
	dp[0][0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<k;j++) dp[i][j]=dp[i-1][j];
		for(int j=0;j<k;j++)
			if(a[i]+j>=k)
				ans=(ans+g[n-i]*dp[i-1][j]%mod)%mod,dp[i][j+a[i]-k]=(dp[i-1][j]+dp[i][j+a[i]-k])%mod;
			else
				dp[i][j+a[i]]=(dp[i-1][j]+dp[i][j+a[i]])%mod;
	}
	cout<<ans<<endl;
	return 0;
}

posted @ 2025-10-26 13:15  Engle_Chen  阅读(15)  评论(0)    收藏  举报