20210923上午
圆桌骑士,好,圆桌骑士。
T1 | T2 | T3 | T4 | T5 | |
---|---|---|---|---|---|
预测 | 100 | 100 | 100 | 100 | 100 |
一测 | 100 | 100 | 100 | 100(结束前没交上去) | 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
n−failn。
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;
}
总结:题目难度尚可,数据是什么____。