• CF610E Alphabet Permutations


    题目传送门

    分析:
    对于两个相邻的字符(a,b),在排列中的位置为(rk_a,rk_b),如果(rk_a>=rk_b)那么必须多用一个模式串
    由于字符集很小,我们开一个线段树,每个节点上有一个(K*K)的数组,(a[i][j])表示某一段区间前一个为(i)后一个为(j)的个数
    维护两端字符可以简单合并,区间修改也可以维护
    复杂度(O(qlognK^2))

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<set>
    
    #define maxn 200005
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    inline int getint()
    {
    	int num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n,m,K;
    int a[maxn<<2][10][10],L[maxn<<2],R[maxn<<2],len[maxn<<2],lz[maxn<<2];
    char s[maxn];
    int rk[10];
    
    inline void update(int i,int x)
    {memset(a[i],0,sizeof a[i]);a[i][x][x]=len[i]-1,L[i]=R[i]=lz[i]=x;}
    inline void pushdown(int i)
    {if(~lz[i])update(i<<1,lz[i]),update(i<<1|1,lz[i]),lz[i]=-1;}
    inline void pushup(int i)
    {
    	int l=i<<1,r=i<<1|1;
    	for(int j=0;j<K;j++)for(int k=0;k<K;k++)a[i][j][k]=a[l][j][k]+a[r][j][k];
    	a[i][R[l]][L[r]]++,L[i]=L[l],R[i]=R[r];
    }
    
    inline void build(int i,int l,int r)
    {
    	len[i]=r-l+1,lz[i]=-1;
    	if(l==r){L[i]=R[i]=s[l]-97;return;}
    	int mid=(l+r)>>1;
    	build(i<<1,l,mid),build(i<<1|1,mid+1,r);
    	pushup(i);
    }
    inline void update(int i,int l,int r,int ql,int qr,int x)
    {
    	if(r<ql||qr<l)return;
    	if(ql<=l&&r<=qr){update(i,x);return;}
    	pushdown(i);
    	int mid=(l+r)>>1;
    	update(i<<1,l,mid,ql,qr,x),update(i<<1|1,mid+1,r,ql,qr,x);
    	pushup(i);
    }
    
    int main()
    {
    	n=getint(),m=getint(),K=getint();
    	scanf("%s",s+1);
    	build(1,1,n);
    	while(m--)
    	{
    		int op=getint();
    		if(op==1)
    		{
    			int l=getint(),r=getint();
    			scanf("%s",s+1);
    			update(1,1,n,l,r,s[1]-97);
    		}
    		else
    		{
    			int ans=1;
    			scanf("%s",s+1);
    			for(int i=1;i<=K;i++)rk[s[i]-97]=i;
    			for(int i=0;i<K;i++)for(int j=0;j<K;j++)if(rk[i]>=rk[j])ans+=a[1][i][j];
    			printf("%d
    ",ans);
    		}
    	}
    }
    

  • 相关阅读:
    STM32|4-20mA输出电路
    Delphi版IP地址与整型互转
    侧方位停车
    98年的‘风暴’,08年的‘危机’,18年的“钱荒‘’
    一些软件设计的原则
    oracle-数据库的各种-锁-详解
    演员李艾佳去世突发病征年仅36岁
    【人生】王石:没变强是因为你太舒服
    耐心看的人早晚会成人上人
    Linux之make的用法讲解
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13255720.html
Copyright © 2020-2023  润新知