2024.4.8 資料結構課件補題

KnightL發表於2024-04-08

[AGC055B] ABC Supremacy

ABC 分別為 1,2,3,然後令 \(s_i=(s_i-i) \text mod 3\) 且結果大於 0。

然後可以發現三種組合均為連貫的三個相同數。且可以自由移動。

可以選擇每遇到三個相同數就刪掉,或者不斷加入棧,如果棧頂三個數相同全部彈出。

再比較剩下的數即可。

#include<bits/stdc++.h>
#define maxn 600100

using namespace std;

int n,cnts,cntt;
int S[maxn],T[maxn];
string a,b;
bool viss[maxn],vist[maxn];
int s[maxn],t[maxn]; 
stack<int> A,B;

int read(){
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
	return s*w;
}

int main(){
	n=read();
	cin>>a>>b;
	for(int i=0;i<n;i++){
		if(a[i]=='A') s[i+1]=1;
		if(a[i]=='B') s[i+1]=2;
		if(a[i]=='C') s[i+1]=3;
		if(b[i]=='A') t[i+1]=1;
		if(b[i]=='B') t[i+1]=2;
		if(b[i]=='C') t[i+1]=3;
		s[i+1]=(s[i+1]-(i+1))%3;
		t[i+1]=(t[i+1]-(i+1))%3; 	
		if(s[i+1]<0) s[i+1]+=3;
		if(t[i+1]<0) t[i+1]+=3; 
	} 
	for(int i=1;i<=n;i++){
		if(A.size()>=2){
			int x=A.top();A.pop();
			int y=A.top();A.pop();
			if(!(x==y&&x==s[i])){
				A.push(y);A.push(x);
				A.push(s[i]);
			}
		}
		else A.push(s[i]);
		if(B.size()>=2){
			int x=B.top();B.pop();
			int y=B.top();B.pop();
			if(!(x==y&&x==t[i])){
				B.push(y);B.push(x);
				B.push(t[i]);
			}
		}
		else B.push(t[i]);
	}

	if(A.size()!=B.size()){
		puts("NO");return 0;
	}
	while(A.size()){
		if(A.top()!=B.top()) {puts("NO");return 0;}
		A.pop();B.pop();
	}

	puts("YES");
	return 0;
}

BZOJ2616 SPOJ PERIODNI

題解做法,注意統計答案的順序。

#include<bits/stdc++.h>
#define maxn 1000100
#define Mod 1000000007 
#define LL long long

using namespace std;

int n,k;
int a[maxn];
LL st[maxn],top;
int ls[maxn],rs[maxn],size[maxn];
LL int f[1010][1010],g[1010][1010];
LL int inv[maxn],mul1[maxn],mul2[maxn];

int read(){
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
	return s*w;
}

LL int C(LL int x,LL int y){
	return y>x?0:mul1[x]*mul2[y]%Mod*mul2[x-y]%Mod;
}

void dfs(int u,int fa){
	if(ls[u])dfs(ls[u],u);
	if(rs[u])dfs(rs[u],u);
	size[u]=size[ls[u]]+size[rs[u]]+1;
	for(int i=0;i<=size[ls[u]];i++){
		for(int o=0;o<=size[rs[u]];o++){
			g[u][i+o]+=f[ls[u]][i]*f[rs[u]][o]%Mod;
			g[u][i+o]%=Mod;
		}
	}
	for(int i=0;i<=size[u];i++){
		for(int o=0;o<=i;o++){
			f[u][i]+=g[u][o]*(C(size[u]-o,i-o)*C(a[u]-a[fa],i-o)%Mod*mul1[i-o]%Mod)%Mod;
			f[u][i]%=Mod;
		}
	}
}
int main(){
	n=read();k=read(); 
	inv[0]=mul1[0]=mul2[0]=1;
	inv[1]=mul1[1]=mul2[1]=1;
	for(LL int i=2;i<=1e6;i++){
		inv[i]=inv[Mod%i]*(Mod-Mod/i)%Mod;
		mul1[i]=mul1[i-1]*i%Mod;
		mul2[i]=mul2[i-1]*inv[i]%Mod;
	}
	for(int i=1,k;i<=n;i++){
		a[i]=read();k=top;
		while(k>0&&a[st[k]]>a[i])k--;
		if(k)rs[st[k]]=i;
		if(k<top)ls[i]=st[k+1];
		st[++k]=i;top=k;
	}
	f[0][0]=1;
	dfs(st[1],0);
	cout<<f[st[1]][k];
}

ICPC2023 Macau Gym104891C

貪心想的話是能選哪種選哪種。

分塊跳跳跳,統計跳出當前塊的步數和位置。

統計一個標記來維護整個塊內部,記錄用哪一種牌。

程式碼實現借鑑了涼笙和課件 std。

#include <bits/stdc++.h>
#define maxn 100010

using namespace std;

int read(){
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
	return s*w;
}

int n,k,len,maxx;
int pos[maxn],L[maxn],R[maxn],a[maxn];
int to[maxn],nxt[maxn],f[maxn],tag[maxn],lstf[maxn];
set<int> s;

void change(int x,int val){
    if(val>0)nxt[x]=val;
    else nxt[x]=x+k;
}

void rebuild(int id){
    for(int i=R[id];i>=L[id];i--){
        if(nxt[i]>R[id]){
        	to[i]=nxt[i];f[i]=1;
			lstf[i]=(!(i>=maxx));
        }
        else{
        	to[i]=to[nxt[i]];f[i]=f[nxt[i]]+1;
			lstf[i]=(i>=maxx)?0:lstf[nxt[i]]+1;
        }
    }
}

void pushdown(int u){
    if(!tag[u]) return;
    for(int i=L[u];i<=R[u];i++)change(i,tag[u]);
    tag[u]=0;
}

void update(int x,int y,int val){
    if(pos[x]==pos[y]){
        pushdown(pos[x]);
        for(int i=x;i<=y;i++)change(i,val);
        rebuild(pos[x]);
        return ;
    }
    pushdown(pos[x]);
    for(int i=x;i<=R[pos[x]];i++)change(i,val);
    rebuild(pos[x]);
    
	pushdown(pos[y]);
    for(int i=L[pos[y]];i<=y;i++)change(i,val);
    rebuild(pos[y]);
    
	for(int i=pos[x]+1;i<pos[y];i++)tag[i]=val;
}

int query(int mx){
    int now=0,res=0;
    while(now<mx){
        if(tag[pos[now]]>0)res++,now=tag[pos[now]];
        else if(tag[pos[now]]==-1)res++,now+=k;
        else {
            if(pos[now]!=pos[mx])res+=f[now],now=to[now];
            else res+=lstf[now],now=to[now];
        }
    }
    return res;
}

int main(){
    int T=read();
    while(T--){
        n=read();k=read();len=sqrt(n);
        for(int i=1;i<=n;i++)
			a[i]=read(),L[i]=R[i]=0;
        
		for(int i=0;i<=n;i++){
            pos[i]=(i-1)/len+1;
            if(!L[pos[i]])L[pos[i]]=i;
            R[pos[i]]=i;
            nxt[i]=to[i]=n+1;
            f[i]=lstf[i]=tag[i]=0;
        }
        
        pos[0]=L[0]=R[0]=0;s.insert(0);
		for(int i=1;i<=n;i++){
            maxx=max(maxx,a[i]);s.insert(a[i]);
            int lst=*(--s.lower_bound(a[i]));
            int l=max(lst,a[i]-k);update(l,a[i]-1,-1);
            if(lst<a[i]-k)update(lst,a[i]-k-1,a[i]);
            int ans=query(maxx);cout<<ans<<" ";
        }
        puts("");
        maxx=0;
    }
    return 0;
}

相關文章