C0376 【20250819】初2025级D组模拟测试_总结
总结
T1
虽说有了思路,但是遇到了一个细节上的错误。导致最后挂成了六十分。
T2
上有了一个部分分的思路打出来了之后。并没有多想,但是最后却意外地拿到了满分。
T3
想到了正解,并将代码打出来了。但是由于在最后一步输出答案的时候没有取模,导致挂了十分。
T4
很快就想出了一个部分的思路,打出来之后就没有往正解去想了。最后拿到了应有的分数。下来补题,发现了一个非常巧妙的做法。
题解
T1
我们会发现,如果说我当前这一位是最高的那一个,需要借位的那一位答案一定是最优的。那么假设当前这一位所对应的十的幂次为 \(i\)。那么答案就是 \(i+a-b\)。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
signed main()
{
int a,b,ans=0;cin>>a>>b;
for(int i=10;i<=a;i*=10) if(a%i-b%i<0) ans=i;
cout<<ans+a-b;
return 0;
}
T2
对于时间复杂度为 \(O(nm)\) 的算法,大家一定都会做,直接暴力模拟即可。
我们会发现当经过一定的周期之后所有牛都会回到最初的起点上。
而至于怎么回去,就是一个简单的小学题。算它每一头牛所对应的周期的最小公倍数即可。
这个时候我们的时间复杂度就会变为 \(O(n\times lcm(a_1,\dots,a_n))\)
最后我们再对每一个时间所对应的这个周期输出即可。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=1e5+5;
int k[maxn],n,m,cnt[maxn],ans[maxn];
vector<int> g[maxn];
int lcm(int x,int y)
{
return x*y/__gcd(x,y);
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int n,m,nm=1;cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>k[i];
g[i].push_back(0);
nm=lcm(nm,k[i]);
for(int j=1;j<=k[i];j++)
{
int x;cin>>x;
g[i].push_back(x);
}
}
nm=min(nm,m);
for(int i=1;i<=nm;i++)
{
int maxx=0,maxi=0;
for(int j=1;j<=n;j++)
{
cnt[j]++;
if(cnt[j]>k[j]) cnt[j]=1;
if(g[j][cnt[j]]>maxx) maxx=g[j][cnt[j]],maxi=j;
}
ans[i]=maxi;
}
int sum=1;
for(int i=1;i<=m;i++)
{
cout<<ans[sum]<<' ';
sum++;
if(sum>nm) sum=1;
}
return 0;
}
T3
我们会发现这道题它无非就是进位或者不进位这两种选项。所以我们可以考虑DP。
设 \(dp_{i,0/1}\) 表示前 \(i\) 位当前最后这一位他到底是进位还是不进位
那么就可以分成下面3种情况。
- 当前这两个数字加起来小于九。那么这个时候无论怎样他都不会进位
- 当前这两个数字加起来等于九,那么这个时候只有上一步进位了之后,他才会进位。
- 当前这两个数字加起来大于九,那么这个时候无论怎样,他都会进位。
而对于所有不进位的情况,他要么本来就不能进位,要么能进位被他忘了。即任何情况他都可以不进位。
那么最后的答案就为 \(dp_{n,0}+dp_{n,1}\)。
记得取模!记得取模!记得取模!
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=2e5+5,mod=1e9+7;
int dp[maxn][2];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
string s,t;cin>>s>>t;
reverse(s.begin(),s.end());
reverse(t.begin(),t.end());
if(s.size()<t.size()) swap(s,t);
while(t.size()<s.size()) t=t+'0';
s=' '+s,t=' '+t;
int len=min(s.size(),t.size());
dp[0][0]=1;
for(int i=1;i<len;i++)
{
int x=s[i]-'0',y=t[i]-'0';
if(x+y<9) dp[i][0]=dp[i-1][0]+dp[i-1][1];
else if(x+y==9) dp[i][0]=dp[i-1][0]+dp[i-1][1],dp[i][1]=dp[i-1][1];
else if(x+y>9) dp[i][0]=dp[i-1][0]+dp[i-1][1],dp[i][1]=dp[i-1][0]+dp[i-1][1];
dp[i][0]%=mod,dp[i][1]%=mod;
}
cout<<(dp[s.size()-1][0]+dp[s.size()-1][1])%mod;
return 0;
}
T4
一个显然的暴力做法,我们枚举于两边的a,然后中间的b我们用排列组合解决即可。
但是这样子显然是过不了且无法优化的。
那我考虑枚举中间的两个b。那么我对于它左边有多少个a和另外一个b右边有多少个a去用排列组合解决即可。
此时我可以选择将后面那个b不枚举。我去看前面那个b,它的前面有多少个a,以及它后面有多少个形如ba的组合。
前面有多少个a是好解决的?至于后面那个我可以将它先求出来后面有多少个a后前面再去拼个b即可
最后就是当前这个b前面有多少个a以及。当前这个B的下一个后面有多少个形如的ba组合即可
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=5e6+5,mod=1e9+7;
int fa[maxn],ba[maxn],bab[maxn];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
string s;cin>>s;
int n=s.size(),ans=0;
s=' '+s;
for(int i=1;i<=n;i++) fa[i]=(fa[i-1]+(s[i]=='a')*i%mod)%mod;
for(int i=n;i>=1;i--)
ba[i]=(ba[i+1]+(s[i]=='a')*(n-i+1)%mod)%mod,
bab[i]=(bab[i+1]+(s[i]=='b')*ba[i]%mod)%mod;
for(int i=1;i<=n;i++) ans=(ans+bab[i+1]*fa[i]%mod*(s[i]=='b')%mod)%mod;
cout<<ans;
return 0;
}
本文来自博客园,作者:Engle_Chen,欢迎转载,转载请注明原文链接:https://www.cnblogs.com/EagleChenzhilong/p/19047423
,感谢阅读!
浙公网安备 33010602011771号