hdu 6190 & hdu 6192

版权声明:原来这里可以拿来卖萌ヽ(・∀・)ノ https://blog.csdn.net/u012345506/article/details/80134756

hdu 6190 Matching in a Tree

容易发现 S 的前缀 S [ 1 , x ] P v 的一个子串满足单调性,即若 S [ 1 , x ] P v 的一个子串,那么 S [ 1 , i ] | 1 i x 必然是 P v 的一个子串。故查询实际上只需要计算对于 P v ,最大的满足要求的 x 是否满足 x p 1
f ( v , l ) 表示 P v 的长度为 l 的后缀是否是 S 的一个前缀, g ( a , l ) 表示在 S 的前缀中,第 l 个位置能否为 a 字符。那么有:
f ( v , l ) = f ( f a t h e r v , l 1 ) g ( A v , l )
用Bitset优化,计算出所有节点的 f 后再求每个节点的 f 的前缀或即可。总复杂度为 O ( 1000 64 n )

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
//--Container
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
//--
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
typedef bitset<1001> bt;
const ll md=1e9+7;const int up=1e6;
bt sd[26],wg[up+10];
struct eg{int u,v,nx;char x;}gp[up+10];int cnt,hd[up+10],qry[up+10][2],qn;
inline ll qni(ll a,ll b){ll r=1;for(;b;b>>=1,a=a*a%md)if(b&1)r=r*a%md;return r;};
inline void psh(int u,int v,char x){++cnt;gp[cnt].u=u,gp[cnt].v=v,gp[cnt].x=x,gp[cnt].nx=hd[u],hd[u]=cnt;};
void dfs(){
    int i,j;stack<int>stk;stk.push(0);for(;!stk.empty();){
        int v=stk.top();stk.pop();for(i=hd[v];i;i=gp[i].nx){
            wg[gp[i].v]=(wg[v]<<1)&sd[gp[i].x-'a'];wg[gp[i].v][0]=1;stk.push(gp[i].v);
        }
    }
    for(stk.push(0);!stk.empty();){
        int v=stk.top();stk.pop();for(i=hd[v];i;i=gp[i].nx){
            wg[gp[i].v]|=wg[v];stk.push(gp[i].v);
        }
    }
};

bool cl(){
    int i,j,a,b,t,d,m;char cz[10],dz[10];if(scanf("%d",&m)==-1)return 0;
    for(i=0;i<26;sd[i++].reset());
    for(d=qn=cnt=0,clr(hd);m;m--){
        scanf("%s",cz);if(cz[1]=='D'){
            scanf("%d %d %s",&a,&b,cz);psh(a,b,cz[0]);
        }
        else if(cz[1]=='S'){
            scanf("%d %d %d",&a,&i,&b);qry[qn][0]=a,qry[qn][1]=b;++qn;
        }
        else{
            scanf("%s %s",cz,dz);for(++d,i=cz[0];i<=dz[0];++i)sd[i-'a'][d]=1;
        }
    }
    wg[0].reset();wg[0][0]=1;dfs();ll rs=0,be=qn?qni(233,qn-1):0,zn=qni(233,md-2);for(i=0;i<qn;++i,be=be*zn%md)
        rs=(rs+be*(wg[qry[i][1]][qry[i][0]]?1:2)%md)%md;
    printf("%lld\n",rs);
    return 1;
};

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    while(cl());
    return 0;
};

hdu 6192 Removing Mountains

容易发现题目实际上是在求修改1个位置后可能的最长公共前后缀。
对于前缀 S [ 1 , x ] 与后缀 S [ n x + 1 , n ] ,除非 S [ 1 , x ] = S [ n x + 1 , n ] ,否则最多只存在2个可修改点使得他们相等:
a = L C P ( S [ 1 , x ] , S [ n x + 1 , n ] ) L C P 指他们的最长公共前缀长度。
那么这2个点为 S a + 1 S n x + a + 1

故用扩展KMP求出 L C P 的值,之后对于每个 x ,分别修改一次对应的2个点,同时用hash判断即可。总复杂度为 O ( n )

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
//--Container
#include<vector>
//--
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
typedef unsigned int ui;
const int up=1e6;const ui bse=131;char cz[up+10];int n,nxt[up+10];ui pr[up+10],xx[up+10];
void _exkmp(){
    int i,j,k,d,t,mx,mz;for(nxt[0]=n,nxt[1]=0,j=1,k=0;j<n&&cz[j]==cz[k];++j,++k)++nxt[1];mx=--j,mz=1;
    for(i=2;i<n;++i){
        if(mx<i){for(nxt[i]=0,j=i,k=0;j<n&&cz[j]==cz[k];++j,++k)nxt[i]++;mx=--j,mz=i;}
        else{
            if(i+nxt[i-mz]-1<mx)nxt[i]=nxt[i-mz];
            else{
                for(nxt[i]=mx-i+1,j=mx+1,k=mx-i+1;j<n&&cz[j]==cz[k];++j,++k)++nxt[i];mx=--j,mz=i;
            }
        }
    }
};

inline ui _seg(int l,int r,int k,char x){
    return pr[r]-(l-1>=0?pr[l-1]:0)*xx[r-l+1]-(k>=l&&k<=r?xx[r-k]*cz[k]-xx[r-k]*x:0);
};

bool cl(){
    int i,j,d,k,t;if(scanf("%d",&n)==-1)return 0;scanf("%s",cz);
    for(xx[0]=1,i=1;i<n;++i)xx[i]=xx[i-1]*bse;for(pr[0]=cz[0],i=1;i<n;++i)pr[i]=pr[i-1]*bse+cz[i];
    for(_exkmp(),i=1;i<n;++i){
        t=nxt[i];if(t+i==n){printf("%d %d\n",i,n);break;}
        else{
            k=0;if(_seg(0,n-1-i,t,cz[i+t])==_seg(i,n-1,t,cz[i+t]))++k;
            if(_seg(0,n-1-i,i+t,cz[t])==_seg(i,n-1,i+t,cz[t]))++k;
            if(k){printf("%d %d\n",i,k);break;}
        }
    }
    if(n==1)printf("1 1\n");
    return 1;
};

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    while(cl());
    return 0;
};

猜你喜欢

转载自blog.csdn.net/u012345506/article/details/80134756
hdu