簡單的字串(迴文子集數+二維線段樹)
阿新 • • 發佈:2018-12-01
題目:
思路:第一步先處理如何計算一個區間的迴文子集個數
構成迴文串,有兩種情況: 1. 每種字母都選偶數個,這樣一定可以構成迴文串
2. 有一種字母選了奇數個,其他的選了偶數個,這樣也一定可以構成迴文串
對於每種字母選偶數個或奇數個的選擇方法數,都可以用二項式定理得到2^(cnt-1)。那麼對應於第一種情況,答案應該是
2^(cnt-1) ,對於第二種情況,應該是C(1,n)*2^(cnt-1) 。最後還要減去空集的情況。
所以最後答案應該是:
第二步就是考慮用二維線段樹去維護區間修改了:
意思就是維護對26個字母都建立一顆線段樹,每顆都取維護該字母在任意區間的數量,修改的時候注意方向。其他的和普通線段樹類似。
程式碼:
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; typedef long long ll; const int mod=1e9+7; #define lson rt<<1 #define rson rt<<1|1 #define Lson l,m,lson #define Rson m+1,r,rson struct Tree { int l,r; int sum[26],lazy; }tree[maxn<<2]; char a[maxn]; void push_up(int rt) { for(int i=0;i<26;i++) { tree[rt].sum[i]=tree[lson].sum[i]+tree[rson].sum[i]; } } void push_down(int rt) { if(tree[rt].lazy==0) return; int t=tree[rt].lazy; int tmp[26]; for(int i=0;i<26;i++) { tmp[i]=tree[lson].sum[i]; } for(int i=0;i<26;i++) { tree[lson].sum[(i+t)%26]=tmp[i]; } for(int i=0;i<26;i++) { tmp[i]=tree[rson].sum[i]; } for(int i=0;i<26;i++) { tree[rson].sum[(i+t)%26]=tmp[i]; } tree[lson].lazy+=t; tree[rson].lazy+=t; tree[rt].lazy=0; } void Build(int l,int r,int rt) { tree[rt].l=l,tree[rt].r=r; if(l==r) { tree[rt].sum[a[l]-'a']++; return; } int m=(l+r)>>1; Build(Lson); Build(Rson); push_up(rt); } void updata(int L,int R,int v,int l,int r,int rt) { if(L<=l&&R>=r) { int tmp[26]; for(int i=0;i<26;i++) { tmp[i]=tree[rt].sum[i]; } for(int i=0;i<26;i++) { tree[rt].sum[(i+v)%26]=tmp[i]; } tree[rt].lazy+=v; tree[rt].lazy%=26; return; } push_down(rt); int m=(l+r)>>1; if(L<=m) { updata(L,R,v,Lson); } if(R>m) { updata(L,R,v,Rson); } push_up(rt); } int query(int i,int L,int R,int l,int r,int rt) { if(L<=l&&R>=r) { return tree[rt].sum[i]; } push_down(rt); int m=(l+r)>>1; int ans=0; if(L<=m) { ans+=query(i,L,R,Lson); } if(R>m) { ans+=query(i,L,R,Rson); } push_up(rt); return ans; } ll fac2[maxn]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif memset(tree,0,sizeof(tree)); fac2[0]=1; for(int i=1;i<maxn;i++) { fac2[i]=fac2[i-1]*2%mod; } int n,q; scanf("%d%d",&n,&q); scanf("%s",a+1); Build(1,n,1); int op,l,r,v; while(q--) { scanf("%d",&op); if(op==1) { scanf("%d%d%d",&l,&r,&v); l++; r++; v=v%26; updata(l,r,v,1,n,1); } else { scanf("%d%d",&l,&r); l++,r++; int s[26]; int cnt=0; ll ans=1; for(int i=0;i<26;i++) { s[i]=query(i,l,r,1,n,1); if(s[i]) { cnt++; } } for(int i=0;i<26;i++) { if(s[i]==0) continue; ans=ans*fac2[s[i]-1]%mod; } ans=ans*(cnt+1)%mod; ans=(ans-1+mod)%mod; printf("%d\n",ans); } } return 0; }