1001
并查集。考虑按点权大到小把点插入图中,每次插入点到图中,我们不妨设集合\(S\)(其中\(s_i\)为第\(i\)个集合的权值)为与当前点相连的连通块组成的集合,\(w\)为当前节点的权值。易得插入一个点得到的新连通块的公式为:
\[\sum^S (s_i-w)+w \]
那么维护集合我们很自然的想到用并查集维护。最后扫一遍每个点,保证每个连通块都加入答案。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll input(){
ll x=0,f=0;char ch=getchar();
while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return f? -x:x;
}
#define PII pair <int,int>
#define fr first
#define sc second
#define mp make_pair
const int N=1e5+7;
int n,m;
ll Ans=0;
vector <int> G[N];
PII a[N];
ll vis[N],ans[N];
int fa[N],rk[N],vs[N];
int find(int x){ return fa[x]==x? x:(fa[x]=find(fa[x]));}
void merge(int x,int y){
x=find(x);y=find(y);
x==y? 0:rk[x]>=rk[y]? fa[y]=x,rk[x]+=rk[y]:fa[x]=y,rk[y]+=rk[x];
}
int main(){
int T=input();
while(T--){
n=input(),m=input();
int sta=1;Ans=0;
for(int i=1;i<=n;i++){
int val=input();
a[i]=mp(val,i);
fa[i]=i,rk[i]=1,G[i].clear();
vis[i]=0,ans[i]=0;vs[i]=0;
}
for(int i=1;i<=m;i++){
int u=input(),v=input();
G[u].push_back(v),G[v].push_back(u);
}
sort(a+1,a+1+n);
for(int i=n;i>=1;i--){
int u=a[i].sc,val=a[i].fr;
int cnt=0;
for(auto v:G[u]){
if(vis[v]){
if(find(u)!=find(v)) ans[u]+=(ans[find(v)]-val);
merge(u,v);
}
}
vis[u]=1;
ans[find(u)]=ans[u]+val;
}
ll res=0;
for(int i=1;i<=n;++i){
if(vs[find(i)]==0) res+=ans[find(i)],vs[find(i)]=1;
}
printf("%lld\n",res);
}
}
1012
比赛的时候dp没推出来,就是菜☹。我们观察到B串非常短\(m\)最大只有20,我们考虑把复杂度尽量与询问的区间长度无关,与B串的长度有关。我们这个时候想到了一个非常好用的结构序列自动机,序列自动机能够让我们在原串上快速移动,这样我们的所有操作就与区间长度无关,而与\(m\)有关了。
现在问题转换为如何通过序列自动机,求区间的LCS,为啥要求LCS,因为我编辑距离只有增加和删除,那么最优一定是尽可能的保留更多的字符不被删除,那么我们就很自然的想到要求LCS,最后答案一定是在原串中要删掉多少个字符\((r-l+1-LCS)\)加上要加入多少个字符使得答案匹配的数量\(|B|-LCS\),即\((r-l+1-LCS)+|B|-LCS\)。我们不妨记区间\([l,r]\)的LCS为\(LCS(l,r)\),那么我们求\(LCS(l,r)\),需要考虑\(dp[i][j]\)表示开始\(B\)的前\(i\)个位置匹配长度为\(j\)的LCS最远能到哪里。那么转移方程易得:
\[dp[i][j]=min(dp[i][j],nxt[dp[i-1][j-1]][s[i]-'a']) \]
最后扫一遍\(dp[m][i]\)求答案即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll input(){
ll x=0,f=0;char ch=getchar();
while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return f? -x:x;
}
const int N=1e5+7;
int nxt[N][27];
char a[N],b[N];
int lena,lenb;
void init(){
memset(nxt,0,sizeof nxt);
int len=strlen(a+1);
for(int i=0;i<26;i++) nxt[len][i]=1e9;
for(int i=len;i>=1;i--){
for(int j=0;j<=25;j++) nxt[i-1][j]=nxt[i][j];
nxt[i-1][a[i]-'a']=i;
}
}
int dp[27][27];
ll getans(int l,int r){
memset(dp,0x3f,sizeof dp);
dp[0][0]=l-1;
for(int i=1;i<=lenb;i++){
dp[i][0]=l-1;
for(int j=1;j<=i;j++){
dp[i][j]=dp[i-1][j];
if(dp[i-1][j-1]<=r){
dp[i][j]=min(dp[i][j],nxt[dp[i-1][j-1]][b[i]-'a']);
}
}
}
int res=1e9;
for(int i=0;i<=lenb;i++){
if(dp[lenb][i]<=r) res=min(res,(r-l+1-i)+(lenb-i));
}
return res;
}
int main(){
int T=input();
while(T--){
scanf("%s%s",a+1,b+1);
init();
lena=strlen(a+1),lenb=strlen(b+1);
int Q=input();
for(int i=1;i<=Q;i++){
int l=input(),r=input();
printf("%lld\n",getans(l,r));
}
}
}