C K-th Substring
k才5,随便做都行。当然也可以SAM求第k大
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <string>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define copy(x,t) memcpy(x,t,sizeof(x))
const int N=100005;
char s[N];
int rec[N][26],size[N],len[N],fa[N];
int b[N],rk[N],last,tot;
void extend(int ch) {
int p,q,np,nq;
p=last; last=np=++tot;
len[np]=len[p]+1;
for (;p&&!rec[p][ch];p=fa[p]) rec[p][ch]=np;
if (!p) fa[np]=1;
else {
q=rec[p][ch];
if (len[q]==len[p]+1) fa[np]=q;
else {
nq=++tot; len[nq]=len[p]+1;
copy(rec[nq],rec[q]);
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
for (;p&&rec[p][ch]==q;p=fa[p]) rec[p][ch]=nq;
}
}
}
void build() {
rep(i,1,tot) b[len[i]]++;
rep(i,1,tot) b[i]+=b[i-1];
rep(i,1,tot) rk[b[len[i]]--]=i;
drp(ti,tot,1) {
int x=rk[ti]; size[x]++;
rep(i,0,25) size[x]+=size[rec[x][i]];
}
}
void kth(int k) {
for (int x=1;k;) {
rep(i,0,25) if (rec[x][i]) {
int y=rec[x][i];
if (size[y]<k) k-=size[y];
else {
putchar('a'+i);
k--,x=y; break;
}
}
}
}
int main(void) { tot=last=1;
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int k; scanf("%s%d",s+1,&k);
int n=strlen(s+1);
rep(i,1,n) {
extend(s[i]-'a');
}
build();
kth(k);
putchar('\n');
return 0;
}
D Equals
把交换看成边,那么一个连通块内的点一定可以随便换
于是我们dfs维护一下连通性,然后开个桶就可以了
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int N=400005;
std:: vector <int> v;
struct edge {int x,y,next;} e[N];
int vis[N],cnt[N],a[N];
int ls[N],edCnt,ans;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,ls[y]}; ls[y]=edCnt;
}
void dfs(int x) {
vis[x]=1; v.push_back(x);
for (int i=ls[x];i;i=e[i].next) {
if (vis[e[i].y]) continue;
dfs(e[i].y);
}
}
int main(void) {
int n=read(),m=read();
rep(i,1,n) a[i]=read();
rep(i,1,m) add_edge(read(),read());
rep(i,1,n) if (!vis[i]) {
v.clear();
dfs(i);
for (int x:v) ++cnt[x];
for (int x:v) if (cnt[a[x]]) ans++;
for (int x:v) --cnt[x];
}
printf("%d\n", ans);
return 0;
}
E Sorted and Sorted
貌似做过的。。
设f[i,j]表示前i个白球j个黑球摆好了,我们讨论第i+j个放什么颜色的球
考虑怎么算加入最后一个球之后增加的答案,很显然就是它和前面i+j-1个球组成的逆序对数量
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int INF=0x3f3f3f3f;
const int N=4005;
int f[N][N],a[N],w[N],b[N];
int cw[N][N],cb[N][N];
int main(void) {
int n; scanf("%d",&n);
rep(i,1,n*2) {
char ch[2]; scanf("%s%d",ch,&a[i]);
if (ch[0]=='W') w[a[i]]=i;
else b[a[i]]=i;
}
rep(i,1,n) {
rep(j,1,i-1) cw[i][0]+=(w[j]>w[i]);
rep(j,1,n) cw[i][j]=cw[i][j-1]+(b[j]>w[i]);
}
rep(i,1,n) {
rep(j,1,i-1) cb[0][i]+=(b[j]>b[i]);
rep(j,1,n) cb[j][i]=cb[j-1][i]+(w[j]>b[i]);
}
rep(i,1,n) f[i][0]=f[i-1][0]+cw[i][0];
rep(j,1,n) f[0][j]=f[0][j-1]+cb[0][j];
rep(i,1,n) rep(j,1,n) {
f[i][j]=std:: min(f[i-1][j]+cw[i][j],f[i][j-1]+cb[i][j]);
}
printf("%d\n", f[n][n]);
return 0;
}
F Monochrome Cat
写死我了。。
很容易想到一个树形dp,设f[i],g[i],h[i]分别表示路径两端都在i黑完整个子树的答案,从i开始黑完整个子树不回到i的答案,路径的两端都在子树内且经过i的答案。
转移的时候要考虑一下i的颜色和儿子的数量
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fi first
#define se second
typedef std:: pair <int,int> pair;
const int INF=0x3f3f3f3f;
const int N=200005;
struct edge {int x,y,next;} e[N*2];
int f[N],g[N],h[N],size[N];
int ls[N],edCnt;
int Ah[N],r[N];
char s[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,ls[y]}; ls[y]=edCnt;
}
void dfs1(int x,int fa) {
size[x]=(s[x]=='W');
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y==fa) continue;
dfs1(e[i].y,x),size[x]+=size[e[i].y];
}
}
void dfs2(int x,int fa) {
int sum=0,son=0;
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y==fa||!size[e[i].y]) continue;
dfs2(e[i].y,x),++son;
sum+=f[e[i].y];
}
if (!son&&s[x]=='W') return (void) (f[x]=g[x]=1);
int wjp=son&1;
f[x]=sum+son+1;
if (s[x]=='W') f[x]+=wjp;
else f[x]+=!wjp;
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y==fa||!size[e[i].y]) continue;
g[x]=std:: min(g[x],sum-f[e[i].y]+g[e[i].y]);
}
g[x]=sum+son;
if (s[x]=='W') g[x]+=!wjp;
else g[x]+=wjp;
g[x]=std:: min(g[x],f[x]);
h[x]=INF;
if (son>1) {
int mx1=0,mx2=0;
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y==fa||!size[e[i].y]) continue;
int v=f[e[i].y]-g[e[i].y];
if (v>mx1) mx2=mx1,mx1=v;
else if (v>mx2) mx2=v;
}
h[x]=sum-mx1-mx2+son-1;
if (s[x]=='W') h[x]+=wjp,r[x]=wjp;
else h[x]+=!wjp,r[x]=!wjp;
}
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y==fa||!size[e[i].y]) continue;
int v=sum-f[e[i].y]+h[e[i].y]+son+2*!r[e[i].y];
int t=(s[x]=='W')?(!wjp):wjp;
if (v+t<h[x]) h[x]=v+t,r[x]=t;
}
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n=read();
rep(i,2,n) add_edge(read(),read());
scanf("%s",s+1);
dfs1(1,0);
dfs2(1,0);
// solve(1,0);
int ans=INF;
rep(i,1,n) {
printf("%d %d %d\n", f[i],g[i],h[i]);
}
rep(i,1,n) if (size[i]==size[1]) {
ans=std:: min(ans,f[i]);
ans=std:: min(ans,g[i]);
ans=std:: min(ans,h[i]);
}
ans=(size[1]<=1)?size[1]:ans;
printf("%d\n", ans);
return 0;
}