一、字符連通塊
數據:對於70%,n、m∈[1,100]
對於100%,n、m∈[1,1000]
其實很簡單,改變一個‘*’變成‘.’,那就會連通其上下左右四個點,那隻要一開始判一下連通塊,然後標記一下就行了。
二、迴文字符序列
數據:對於30%,n∈[1,20]
對於60%,n∈[1,100]
對於100%,n∈[1,2000]
對於30%,可以二進制枚舉,然後判選出來的點能否組成迴文,這很簡單。
後來我先用記憶化搜索,dp[L][R] 表示[L,R]區間內的方案數,然後每次對於一個[L,R]收集一下就行了。這個也不細講。這樣寫可以過n∈[1,400]的
從記憶化搜索改成循環dp。按照上面的思想,定義dp[i][j] 表示長度爲i起點爲j的字符串的方案數。轉移其實也很簡單,玄學轉移。
如果A[j]==A[j+i-1],即這段字符串兩端相等,那就可以把中間的一段dp值加過來。
所有情況下,要把小區間的dp值轉到大區間
#include<bits/stdc++.h>
#define Mod 100007
using namespace std;
char A[2005],B[25];
int n,dp[2005][2005];
int main(){
scanf("%s",A+1);
n=strlen(A+1);
for(int i=1;i<=n;i++)dp[1][i]=1;
for(int i=2;i<=n;i++)
for(int j=1;j+i-1<=n;j++){
if(A[j]==A[j+i-1])dp[i][j]=(dp[i][j]+dp[i-2][j+1]+1)%Mod;//A[j]=A[j+i-1]的情況
dp[i][j]=(dp[i][j]+dp[i-1][j]+dp[i-1][j+1]-dp[i-2][j+1]+Mod)%Mod;//一般情況
}
printf("%d\n",dp[n][1]);//從1開始長度爲n
return 0;
}
三、刪邊最小生成樹
數據:對於50%,n∈[1,300],m∈[1,3000]
對於100%,n∈[1,5000],m∈[1,200000]
一看完題覺得就和安全路徑拿到一模一樣。
先變成最小生成樹,然後把樹外面的邊排個序每條邊連進去,然後就會形成一個環。
然後每次更新完後把路徑壓縮一下,用並查集就行了,這樣可以少更新一些邊。這樣就很快了。
其實寫暴力也可以過,每次把連進去的邊的兩個端點一直往上走,邊走邊更新所有邊。
#include<bits/stdc++.h>
#define M 200005
using namespace std;
int n,m,len;
struct node1{int x,y,v,id;}A[M];
int Fa[M];
bool Q[M];
int find(int x) {return x==Fa[x]?x:Fa[x]=find(Fa[x]);}
bool cmp(node1 a,node1 b){return a.v<b.v;}
int fa2[3][M],dep[M],fa[M],ans[M];
struct node2{int to,id,v;};
vector<node2>edge[M];
void f(int x,int fa1,int id,int v){
fa2[0][x]=fa1;fa2[1][x]=id;fa2[2][x]=v;
dep[x]=dep[fa1]+1;
for(int i=0;i<(int)edge[x].size();i++){
int y=edge[x][i].to;
if(y==fa1)continue;
f(y,x,edge[x][i].id,edge[x][i].v);
}
}
int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)ans[i]=2e9;
for(int i=1;i<=m;i++){scanf("%d %d %d",&A[i].x,&A[i].y,&A[i].v);A[i].id=i;}
sort(A+1,A+m+1,cmp);
for(int i=1;i<=n;i++)Fa[i]=i;
for(int i=1;i<=m;i++){//先把最小生成樹造出來
int x=A[i].x,y=A[i].y;
int f1=find(x),f2=find(y);
if(f1==f2)continue;
edge[x].push_back((node2){y,A[i].id,A[i].v});
edge[y].push_back((node2){x,A[i].id,A[i].v});
len+=A[i].v;Q[A[i].id]=1;Fa[f1]=f2;
}
for(int i=1;i<=n;i++)fa[i]=i;
f(1,0,0,0);//造樹,並把樹上的邊的id,權值,端點處理出來
for(int i=1;i<=m;i++){
if(Q[A[i].id])continue;//只枚舉不在樹上的邊
else {
int x=A[i].x,y=A[i].y,v=A[i].v;
while(x!=y){//往上走,併合並
if(dep[x]>dep[y]){
if(ans[fa2[1][x]]==2e9)ans[fa2[1][x]]=len-fa2[2][x]+v;
fa[x]=fa2[0][x];
x=Find(x);
}else{
if(ans[fa2[1][y]]==2e9)ans[fa2[1][y]]=len-fa2[2][y]+v;
fa[y]=fa2[0][y];
y=Find(y);
}
}
ans[A[i].id]=len;//更新
}
}
for(int i=1;i<=m;i++)
if(ans[i]==2e9)printf("%d\n",-1);
else printf("%d\n",ans[i]);
return 0;
}
差點就AK了,網站上對了,交上去卻只有250啊…………