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种情况。

  1. 当前这两个数字加起来小于九。那么这个时候无论怎样他都不会进位
  2. 当前这两个数字加起来等于九,那么这个时候只有上一步进位了之后,他才会进位。
  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;
}
posted @ 2025-08-19 20:45  Engle_Chen  阅读(14)  评论(0)    收藏  举报