2024.11.14&2024.11.15模拟赛( — _ — )

14日:

四个小时的模拟赛,四道小清新计数题。前面时间状态还是不太好,一个多小时把T1搞出来了,T2T3T4都不会,暴力也没打成。

T1又顺便挂了20分,所以最后总分只有80。是得好好调整状态了。

题目大链接


T1【字符串】

题目大意:

给出两个字符串s,t,要求求出所有x的个数,使得x=p+qp,q分别是s串的非空前缀、t串的非空后缀)

n=|s|,m=|t|,1n,m106

解题思路:

所有x的个数即为n×m,但由于s,t串中重复的字符拼接时会导致相同的x被统计两次,所以需要统计字符串中相同的字符后去重,总数减去一个字符在s串出现的次数乘在t串中出现的次数即可。

但!注意到前后缀非空,所以统计字符时要跳过s1tm

挂分小技巧:取模出错。

坏代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
const int MOD=998244353;
char s1[N],s2[N];
int a1[N],a2[N];
int cnt1,cnt2;
int bx1[N],bx2[N];
int ans;

signed main()
{
	scanf("%s%s",s1,s2);
	for (int i=0;s1[i]!='\0';i++) a1[++cnt1]=(int)(s1[i]-'a');//闲的
	for (int i=0;s2[i]!='\0';i++) a2[++cnt2]=(int)(s2[i]-'a');
	ans=(cnt1*cnt2)%MOD;
	for (int i=2;i<=cnt1;i++) bx1[a1[i]]++;
	for (int i=1;i<cnt2;i++) bx2[a2[i]]++;
	
	for (int i=0;i<26;i++) ans=(ans-(bx1[i]*bx2[i])%MOD+MOD)%MOD;//注!意!取!模!
	printf("%lld",ans);
	return 0;
}

T2【艾特扣德】

待补。

15日:

抽象的题目。不多做评价了。

打了T1的正解,T2的“暴力”,预计总分140。但T1没注意到Σn106,多测初始化初始炸了;T2数据太水,导致暴力完全能过,但是因特判特殊数据特判的不对所以炸了,实际上T1 60分,T2 80分,总分140分。一切的一切都说得过去,但是……

挂了整整60分!!再次与第二失之交臂!!!

题目小链接


T1【最优排序】

题目大意:

给出一个值域为[1,n]的排列p,每次操作可以选取至多四个互不相同的位置,并任意交换他们的位置。求最少操作几次可以使p升序排列。(1T,n,Σn106)

解题思路:

看到这道题又手模了一会儿,突然联想到之前模拟赛的T3,于是就开始非常激动地建图……统计……然后炸了。

我们可以将不好的pi指向i,我们可以想到一定存在若干个pi,交换他们之间的位置后一定合法,手模后发现这些pi会形成一个环。于是乎,我们可以建图后统计出所有环的节点个数以计算答案。

对于一个节点数量为ti的环,我们可以先取到相邻4个节点并进行交换,我们容易发现一次操作会产生一个不合法的pi与三个合法的pj,那么下一次操作包含上次不合法的pi与3个新的pj即可,重复以上操作就可以使整个环合法。

所以,对于该环就要操作ti3次。但是!可以想到,要是最后只用操作两个点的话,那么这次操作可以和其他环一起操作,最后答案即Σi=1mti3+Σi=1m[timod3=2]2

因为这题情况非常简单,所以根本不用跑Tarjan,跑个dfs就行。且,初始化补药memset,重复到n就行,不然会炸。

坏代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int T;
int n;
int p[N];
vector <int> e[N];
int vis[N];
int ans,tol;

void init()
{
	for (int i=0;i<=n;i++) e[i].clear();
	for (int i=0;i<=n;i++) vis[i]=0;
	ans=tol=0;
}
int dfs(int x)
{
	vis[x]=1;
	int res=1;
	int _size=e[x].size();
	for (int i=0;i<_size;i++)
	{
		int v=e[x][i];
		if (vis[v]) continue;
		res+=dfs(v);
	}
	return res;
}
signed main()
{
	scanf("%lld",&T);
	while (T--)
	{
		init();
		scanf("%lld",&n);
		for (int i=1;i<=n;i++)
		{
			scanf("%lld",&p[i]);
			if (p[i]==i) continue;
			e[i].push_back(p[i]);
		}
		for (int i=1;i<=n;i++)
		{
			if (!vis[i]&&p[i]!=i)
			{
				int cnt=dfs(i);
				ans+=cnt/3;
				if (cnt%3==2) tol++;
			}
		}
		printf("%lld\n",ans+(tol+1)/2);
	}
	return 0;
}

T2【图上移动】

题目大意:

给出一个n个节点、m条边的无向图,可以给每个点赋值,要求找到一条最长的路径,使得每次移动都是向当前节点相邻权值最小的节点移动。(1n40)

解题思路:

爆搜。期望得分100,特判失败,实际得分80。

容易发现,我们的路径上不能走完一个环,否则无法达到要求。所以直接枚举起点dfs,若与当前节点相连的节点曾经走过的话,那么当前节点不可走,直接return回去即可。

神奇代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=50;
int n,m; 
vector <int> e[N];
int ans;
int vis[N];

void dfs(int x,int _fa,int tol)
{
	vis[x]=vis[_fa]+1;
	int _size=e[x].size();
	for (int i=0;i<_size;i++)
	{
		int v=e[x][i];
		if (v!=_fa&&vis[v]) return ;
	}
	for (int i=0;i<_size;i++)
	{
		int v=e[x][i];
		if (v==_fa) continue;
		dfs(v,x,tol+1);
		vis[v]=0;
	}
	ans=max(ans,tol);
	return;
}
signed main()
{
	scanf("%lld%lld",&n,&m);
	for (int i=1,u,v;i<=m;i++)
	{
		scanf("%lld%lld",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	for (int i=1;i<=n;i++) 
	{
		memset(vis,0,sizeof vis);
		dfs(i,0,1);
	}
	printf("%lld",ans);
	return 0;
}

posted @   还是沄沄沄  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示