2026 · CSP-S · 二十连测 · 模拟四 题解

T1

不难发现,当只要有任意一组。之间的数字个数大于等于9那么答案一定为9

对于小于等于的情况。直接枚举即可。

代码

点击查看代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
void solve()
{
	int l1,r1,l2,r2,ans=0;cin>>l1>>r1>>l2>>r2;
	if(r1-l1+1>=10||r2-l2+1>=10)
	{
		cout<<9<<endl;
		return;
	}
	for(int i=l1;i<=r1;i++)
		for(int j=l2;j<=r2;j++)
		{
			int x=i+j;
			while(x) ans=max(ans,x%10),x/=10;
		}
	cout<<ans<<endl;
}
signed main()
{
	freopen("digit.in","r",stdin); 
	freopen("digit.out","w",stdout); 
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;cin>>t;
	while(t--) solve();
	return 0;
}

T2

由于只能翻转,所以一个点最多关两个位置

把两个位置都是0的,一个位置是0,一个位置是1的,还有全部都是1的情况,单独筛选出来进行枚举就行。

代码

点击查看代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=1e6+5;
int n,m,mod=1e9+7;
int vis[maxn],cnt;
vector<int> v[maxn];
vector<pair<int,int> > g[maxn];
string s;
void dfs(int x)
{
	for(auto to:g[x])
	{
		if(!vis[to.first]) vis[to.first]=vis[x]^to.second,dfs(to.first);
		else if((vis[to.first]^vis[x])!=to.second)
		{
			cnt=-1;
			return;
		}
 	}
}
void solve()
{
	cin>>n>>m;            
	for(int i=1;i<=m;i++) v[i].clear();
	for(int i=1;i<=n;i++)
	{
		vis[i]=0;g[i].clear();
		cin>>s;
		s=' '+s;                            
		for(int j=1;j<=m;j++) if(s[j]=='1') v[j].push_back(i);
	}
	for(int i=1;i<=(m+1)/2;i++)
	{              
		if(v[i].size()+v[m-i+1].size()>2)
		{
			cout<<0<<endl;
			return;
		}
		int s1=-1,s2=-1;
		for(int x:v[i])
			if(s1==-1)s1=x;
			else s2=x;
		for(int x:v[m-i+1])
			if(s1==-1) s1=x;
			else s2=x;
		if(s2>0)
		{               
			if(v[i].size()==v[m-i+1].size())
			{
				g[s1].push_back({s2,0});
				g[s2].push_back({s1,0});
			}
			else
			{
				g[s1].push_back({s2,1});
				g[s2].push_back({s1,1});
			}
		}
	}
	cnt=0;
	for(int i=1;i<=n&&cnt!=-1;i++)
		if(!vis[i])
		{
			cnt++;
			int u=i;
			vis[i]=2;
			dfs(i);
		}
	if(cnt==-1)
	{
		cout<<0<<endl;
		return;
	}
	int ans=1;
	while(cnt--) ans=ans*2%mod;
	cout<<ans<<endl;
}
signed main()
{
	freopen("reverse.in","r",stdin);
	freopen("reverse.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;cin>>t;
	while(t--) solve();
	return 0;
}

T3

遇到这种只差1的有两种做法。要么就是差分,要么就是减掉它对应的序号。

显然,这道题减掉序号会更好做。

这样题目就会转换成最大的连续段。

用双指针和对顶堆即可。

代码

点击查看代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
int a[maxn];
signed main()
{
	freopen("subarray.in","r",stdin);
	freopen("subarray.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;cin>>t;
	while(t--)
	{
		int n,k;cin>>n>>k;
		multiset<int> q2;
		multiset<int,greater<int> > q1;
		for(int i=1;i<=n;i++) cin>>a[i],a[i]-=i;
		int sum1=0,sum2=0,ans=0;
		for(int l=1,r=1;r<=n;r++)
		{
			q1.insert(a[r]);
			sum1+=a[r];
			while(q1.size()>q2.size()) q2.insert(*q1.begin()),sum1-=*q1.begin(),sum2+=*q1.begin(),
									   q1.erase(q1.begin());
			while(q1.size()<q2.size()) q1.insert(*q2.begin()),sum2-=*q2.begin(),sum1+=*q2.begin(),
									   q2.erase(q2.begin());
			int cnt=sum2-q2.size()*(*q1.begin())+q1.size()*(*q1.begin())-sum1;
			while(cnt>k&&l<r)
			{
				if(q1.find(a[l])!=q1.end()) q1.erase(q1.find(a[l])),sum1-=a[l];
				else q2.erase(q2.find(a[l])),sum2-=a[l];
				while(q1.size()>q2.size()) q2.insert(*q1.begin()),sum1-=*q1.begin(),sum2+=*q1.begin(),
									   q1.erase(q1.begin());
				while(q1.size()<q2.size()) q1.insert(*q2.begin()),sum2-=*q2.begin(),sum1+=*q2.begin(),
									   q2.erase(q2.begin());
				cnt=sum2-q2.size()*(*q1.begin())+q1.size()*(*q1.begin())-sum1;
				l++;
			}
			ans=max(ans,r-l+1);
		}
		cout<<ans<<endl;
	}
	return 0;
}

T4

会发现,这道题是一道树形背包

而背包本身的时间复杂度。可能会超。

于是,我们会发现。背包原来的时间复杂度,它在k小于等于n的算数平方根时。背包本身是完全可以跑的。而它大于时显然,这个时候,他的联通块个数就小于了

所以在k大于n的算数平方根时,我们的背包的容量换为联通块个数。

最后照常做背包即可。

代码

点击查看代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5,mod=998244353;
map<int,int> dp[maxn];
int n,k;
vector<int> g[maxn];
void merge(int u,int v)
{
    map<int,int> mp;
    int num=0;
    if (dp[v].count(k)) num+=dp[v][k],num%=mod;
    if (dp[v].count(k+1)) num+=dp[v][k+1],num%=mod;
    for(auto i:dp[u])
	{
        int x=i.first,y=i.second;
        if(num) mp[x]+=y*num%mod,mp[x]%=mod;
        for(auto j:dp[v]) 
        {
            int x2=j.first,y2=j.second;
            if (x+x2>k+1) break;
            mp[x+x2]+=y*y2%mod,mp[x+x2]%=mod;
        }
    }
    dp[u].swap(mp);
    dp[v].clear();
}
void dfs(int x,int fa)
{
    dp[x][1]=1;
    for(auto to:g[x])
    {
        if(to==fa) continue;
        dfs(to,x);
        merge(x,to);
    }
}
signed main()
{
	freopen("partition.in","r",stdin); 
	freopen("partition.out","w",stdout); 
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;cin>>t;
    while(t--)
	{
        cin>>n>>k;
        for(int i=1;i<=n;i++)
		{
            g[i].clear();
            dp[i].clear();
        }
        for(int i=1;i<n;i++)
		{
            int u,v;
            cin>>u>>v;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(1,0);
        int ans=0;
        if(dp[1].count(k))
		{
            ans+=dp[1][k];
            ans%=mod;
        }
        if(dp[1].count(k+1)) ans+=dp[1][k+1],ans%=mod;
        cout<<ans<<endl;
    }
	return 0;
}

posted @ 2026-09-08 22:35  Engle_Chen  阅读(18)  评论(0)    收藏  举报