20210923上午

20210923上午

圆桌骑士,好,圆桌骑士。
请添加图片描述

T1T2T3T4T5
预测100100100100100
一测100100100100(结束前没交上去)0

T1:
导弹拦截翻版,求不下降升子序列数量等于最长下降子序列。
T2:
t m d tmd tmd,为啥 n = 1 e 5 + 5 n=1e5+5 n=1e5+5能用 O ( n 3 ) O(n^3) O(n3)跑过去啊,全是 a a a都能直接卡死的啊。
你想了半天正解,你把它写了下来,你对着自己造的数据调了半天把它调出来了,你甚至写了一个对拍来验证你算法的正确性。
然后你发现拍子过了。。。
你像个小丑。
请添加图片描述
k m p kmp kmp应用,以每个字符串为开头跑 k m p kmp kmp,一直跳 f a i l fail fail,如果有 f a i l fail fail满足长度小于原来的一半且大于 k k k则统计答案,在极端情况下复杂度 O ( n 3 ) O(n^3) O(n3)
然后就过了。。。
事实上没必要每次都往回一直跳,可以记录一个 m n mn mn数组统计一路 f a i l fail fail中大于 k k k的最小值,每次判断一下是否小于一半即可,复杂度 O ( n 2 ) O(n^2) O(n2)
转移:

for(int i=1;i<=n;i++)
{
	memset(mn,0x3f,sizeof(mn));
	fail[i]=i-1;
	for(int j=i+1,t=i-1;j<=n;j++)
	{
		for(;t!=i-1&&s[j]!=s[t+1];t=fail[t]);
		fail[j]=(s[j]==s[t+1]?++t:i-1);
		if(t-i+1>=k) mn[j]=min(mn[t],t-i+1);
		if(mn[j]<=(j-i)/2) ans++;
	}
}

T3:
做过的,见前。
T4:
k m p kmp kmp b o a d e r boader boader性质,若字符串存在最小循环节,则为 n − f a i l n n-fail_n nfailn
T5:
考试点双边双判断错了。。。挂完了。
建反图,表示可以牵手的人,先找点双,在每个点双内找奇环,染色即可,染得出来说明点双内的点都不用踢。
小贴一波

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,m,a,b,ans;
bool s[N][N],p[N],can[N];
int dfc,dfn[N],low[N],id[N];
int cnt=0,h=0,sta[N],d[N][N],num[N];
int vis[N];
void init()
{
	ans=dfc=cnt=0;
	memset(can,false,sizeof(can));
	memset(vis,-1,sizeof(vis));
	memset(s,false,sizeof(s));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(num,0,sizeof(num));
	memset(id,0,sizeof(id));
	return;
}
void tarjan(int x,int fa)
{
	dfn[x]=low[x]=++dfc;sta[++h]=x;
	bool flag=false;
	for(int i=1;i<=n;i++)
	{
		if(s[i][x]||x==i) continue;
		flag=true;
		if(!dfn[i])
		{
			tarjan(i,x);
			low[x]=min(low[x],low[i]);
			if(low[i]>=dfn[x])
			{
				cnt++;
				while(sta[h]!=i) d[cnt][++num[cnt]]=sta[h--];
				d[cnt][++num[cnt]]=sta[h--];
				d[cnt][++num[cnt]]=x;
			}
		}
		else if(i!=fa) low[x]=min(low[x],dfn[i]);
	}
	if(!flag&&!fa) d[++cnt][++num[cnt]]=x;
	return;
}
bool Dfs(int x,int c)
{
	vis[x]=c;
	for(int i=1;i<=n;i++)
	{
		if(i==x||s[x][i]||id[i]!=id[x]) continue;
		if(vis[i]!=-1) {if(vis[i]==c) return true;}
		else if(Dfs(i,c^1)) return true;
	}
	return false;
}
int main()
{
	while(scanf("%d%d",&n,&m)&&n+m)
	{
		init();
		for(int i=1;i<=m;i++) scanf("%d%d",&a,&b),s[a][b]=s[b][a]=true;
		for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,0);
		for(int i=1;i<=cnt;i++)
		{
			for(int j=1;j<=num[i];j++) id[d[i][j]]=i,vis[d[i][j]]=-1;
			if(Dfs(d[i][1],0)) for(int j=1;j<=num[i];j++) can[d[i][j]]=true;
		}
		for(int i=1;i<=n;i++) ans+=can[i]^1;
		printf("%d\n",ans);
	}
	return 0;
}

总结:题目难度尚可,数据是什么____。
请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值