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种情况。
- 修改的就是本层,所以直接把它移到一或者 \(n\) 即可。
- 修改的那一层在我这一层之上,那么无非就是往上走一格,或者是不动。
- 修改的那一层,在我这一层之下,那么无非就是往下走一格或者不动。
对于后两种情况,我们会发现它一定在这一个区间内。而对于第一种情况的话,我们直接给它再开两个区间,即最贴着左边的以及贴着右边的。这三个区间,再去枚举即可。
注意如果说当前这个区间只有一个点,且做了第一种操作,那么此时我们就得把当前这个区间删掉。
代码
#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;
}
本文来自博客园,作者:Engle_Chen,欢迎转载,转载请注明原文链接:https://www.cnblogs.com/EagleChenzhilong/p/19228097
,感谢阅读!
浙公网安备 33010602011771号