2025 --【J+S 二十连测】-- 第十三套 总结

总结

T1,T2,T3

考试时很快就做出来了,没什么问题。

T4

考上没有什么思路,没有打出来部分分。

T5

考试时打个部分分,但是打挂了。

题解

T1

周期问题。直接求出到底经过了多少个周期之后再把零的求出来即可。

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
signed main()
{
	freopen("production.in","r",stdin);
	freopen("production.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;cin>>t;
	while(t--)
	{
		int n,a,b,c;cin>>n>>a>>b>>c;
		int x=n/(a+b+c)*(a+b+c),y=x/(a+b+c)*3;
		if(x>=n)
		{
			cout<<y<<endl;
			continue;
		}
		x+=a,y++;
		if(x>=n)
		{
			cout<<y<<endl;
			continue;
		}
		x+=b,y++;
		if(x>=n)
		{
			cout<<y<<endl;
			continue;
		}
		
		x+=c;y++;
		if(x>=n)
		{
			cout<<y<<endl;
			continue;
		}
	}
	return 0;
}

T2

容易发现,如果说我的上面那一排已经固定了,那么我直接去改下面那一排就行。所以说我们现在的问题就变成了如何将上一排的大小固定。

发现题目要求厚度只能减少,不能增加。所以直接枚举是否需要剪即可。

代码

#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],b[maxn];
signed main()
{
	freopen("bookshelf.in","r",stdin);
	freopen("bookshelf.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n,x,ans=0;cin>>n>>x;
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
	for(int i=2;i<=n;i++)
	{
		if(a[i]>=a[i-1])
		{
			ans+=max(0ll,a[i]-a[i-1]-x);
			a[i]=min(a[i],a[i-1]+x);
		}
		else
		{
			int now=i-1;
			while(now>1&&a[now]-a[now+1]>x)
			{
				ans+=a[now]-a[now+1]-x;
				a[now]=a[now+1]+x;
			}
		}
	}
	int minn=inf;
	for(int i=1;i<=n;i++) minn=min(minn,a[i]+b[i]);
	for(int i=1;i<=n;i++) ans+=a[i]+b[i]-minn;
	cout<<ans;
	return 0;
}

T3

其实题目我们通过小规模的枚举会发现它其实无非就3种情况。

  1. 修改的就是本层,所以直接把它移到一或者 \(n\) 即可。
  2. 修改的那一层在我这一层之上,那么无非就是往上走一格,或者是不动。
  3. 修改的那一层,在我这一层之下,那么无非就是往下走一格或者不动。

对于后两种情况,我们会发现它一定在这一个区间内。而对于第一种情况的话,我们直接给它再开两个区间,即最贴着左边的以及贴着右边的。这三个区间,再去枚举即可。

注意如果说当前这个区间只有一个点,且做了第一种操作,那么此时我们就得把当前这个区间删掉。

代码

#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("agent.in","r",stdin);
	freopen("agent.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int t;cin>>t;
	while(t--)
	{
		int n,m,q;cin>>n>>m>>q;
		for(int i=1;i<=q;i++) cin>>a[i];
		int l[4]={},r[4]={},lt=2,rt=2;
		l[lt]=r[lt]=m;
		l[1]=r[1]=1;
		r[3]=l[3]=n;
		for(int i=1;i<=q;i++)
		{
			int f=0;
			for(int j=lt;j<=rt;j++)
			{
				if(r[j]==-1) continue;
				if(l[j]<=a[i]&&r[j]>=a[i])
				{
					f=1;
					if(l[j]==r[j]) l[j]=0,r[j]=-1;
					if(r[1]==-1) r[1]=l[1]=1;
					if(r[3]==-1) l[3]=r[3]=n;
				}
				else
				{
					if(l[j]>a[i]) l[j]--;
					if(r[j]<a[i]) r[j]++;
				}
			}
			if(f) lt=1,rt=3;
			if(r[1]!=-1&&r[2]!=-1&&l[2]<=r[1]) l[1]=0,r[1]=-1,l[2]=1;
			if(r[3]!=-1&&r[2]!=-1&&r[2]>=l[3]) l[3]=0,r[3]=-1,r[2]=n;
			if(r[1]!=-1&&r[3]!=-1&&r[1]>=l[3]) l[1]=0,r[1]=-1,l[3]=1;
			int ans=0;
			for(int j=lt;j<=rt;j++) ans+=r[j]-l[j]+1;
			cout<<ans<<' ';
		}
		cout<<endl;
	}
	return 0;
}

T4

不难发现,我们设零的个数为 \(num_0\),一的个数为 \(num_1\)。那么他的必胜状态一定为 \(num_0-3num_1\ge 2\)\(num_0-3num_1=-1\)

那么此时直接去用前缀和来判断这个区间即可。

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5;
int cnt[maxn*5];
signed main()
{
	freopen("orchard.in","r",stdin);
	freopen("orchard.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n;string s;cin>>n>>s;
	s=' '+s;
	int now=n*3,sum=0,ans=0;
	cnt[now]++;
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='0')
		{
			now++;
			sum+=cnt[now-2];
		}
		else
		{
			for(int i=0;i<=2;i++) sum-=cnt[now-2-i];
			now-=3;
		}
		ans+=cnt[now+1]+sum;
		cnt[now]++;
	}
	cout<<ans<<endl;
	return 0;
}

T5

由前两个让你可以得到。这道题需要同时运用DP和组合数学。

会发现最长不下降子序列可以看成一段一段的形式。

不是对我们所有可以选择的区间进行一个离散化。

这样子我们就可以得到一个 \(dp_{i,j}\) 表示前 \(i\) 个数。当前已经在 \(j\) 段的方案数。

可以得到转移方程:

\[dp_{i,j}=\sum_{k=1}^{i-1}\sum_{p>j}dp_{k,p}\times C^{len-1}_{len+i-k-1} \]

最里面一层求和,用前缀和优化即可。

代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=600,mod=998244353;
int dp[maxn*2][maxn*2],c[maxn*2],l[maxn],r[maxn],re[maxn*2];
int kasumi(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}
signed main()
{
	freopen("xulie.in","r",stdin);
	freopen("xulie.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n,rcnt=0;cin>>n;
	for(int i=1;i<=n;i++)
	{
        cin>>l[i]>>r[i];
        re[++rcnt]=l[i];
        re[++rcnt]=++r[i];
    }
	sort(re+1,re+rcnt+1);
    rcnt=unique(re+1,re+rcnt+1)-re-1;
    for(int i=1;i<=n;i++)
    {
        l[i]=lower_bound(re+1,re+rcnt+1,l[i])-re;
        r[i]=lower_bound(re+1,re+rcnt+1,r[i])-re;
    }
    dp[0][rcnt]=1,re[rcnt+1]=114514;
    for(int i=1;i<=rcnt;i++) dp[0][i]=1;
    for(int i=1;i<=n;i++)
    {
    	for(int j=l[i];j<r[i];j++)
    	{
    		int len=re[j+1]-re[j];
    		c[1]=len;
    		for(int k=2;k<=i;k++) c[k]=c[k-1]*(len+k-1)%mod*kasumi(k,mod-2)%mod;
    		for(int k=i-1;k>=0;k--)
    		{
    			dp[i][j]=(dp[i][j]+dp[k][j+1]*c[i-k]%mod)%mod;
    			if(j<l[k]||j>=r[k]) break;
    		}
    	}
    	for(int j=rcnt-1;j>=1;j--) dp[i][j]=(dp[i][j]+dp[i][j+1])%mod;
    }
    cout<<dp[n][1];
	return 0;
}
posted @ 2025-11-16 14:10  Engle_Chen  阅读(4)  评论(0)    收藏  举报