zoukankan      html  css  js  c++  java
  • HDU 6155 Subsequence Count(矩阵乘法+线段树+DP)

    题意

    给定一个长度为 (n)(01) 串,完成 (m) 种操作——操作分两种翻转 ([l,r]) 区间中的元素、求区间 ([l,r]) 有多少个不同的子序列。

    (1 leq n,m leq 10^5)

    思路

    看到这种题目,应该条件反射的去想一下线段树。

    但首先还是从一个询问开始,对于一个长度为 (n) 的串,设 (dp_{i,j}) 为前 (i) 位组成的序列中,以 (j) 结尾的串的个数,若串的第 (i) 位为 (j) 有递推式:

    (dp_{i,j}=dp_{i-1,0}+dp_{i-1,1}+1)

    (dp_{i,!j}=dp_{i-1,!j})

    上式是以 (0j,1j) 结尾的串的个数,加上单独一个(j) ;下式则直接转移上一位的信息。

    那么将 ({dp_{0,0},dp_{0,1},1}) 作为初始矩阵,用线段树维护区间对应的转移矩阵即可。

    代码

    #include<bits/stdc++.h>
    #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
    #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
    typedef long long LL;
    using namespace std;
    const int N=1e5+5;
    const int P=1e9+7;
    struct Matrix
    {
    	int n,m,a[4][4];
    	int *operator [](const int x){return a[x];}
    	void resize(int _n,int _m){n=_n,m=_m;}
    	Matrix operator *(const Matrix &_)const
    	{
    		Matrix res;res.resize(n,_.m);
    		FOR(i,1,n)FOR(j,1,_.m)
    		{
    			res[i][j]=0;
    			FOR(k,1,m)(res[i][j]+=1ll*a[i][k]*_.a[k][j]%P)%=P;
    		}
    		return res;
    	}
    	void flip()
    	{
    		swap(a[1][1],a[2][2]);
    		swap(a[1][2],a[2][1]);
    		swap(a[3][1],a[3][2]);
    	}
    	Matrix operator *=(const Matrix &_){return (*this)=(*this)*_;}
    };
    const Matrix Zero=(Matrix){
    	3,3,
    	0,0,0,0,
    	0,1,0,0,
    	0,1,1,0,
    	0,1,0,1};
    const Matrix One =(Matrix){
    	3,3,
    	0,0,0,0,
    	0,1,1,0,
    	0,0,1,0,
    	0,0,1,1};
    Matrix nd[N<<2],A;
    int tag[N<<2];
    char str[N];
    
    void build(int k,int l,int r)
    {
    	tag[k]=0;
    	if(l==r)
    	{
    		if(str[l]=='0')nd[k]=Zero;
    		else nd[k]=One;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	nd[k]=nd[k<<1]*nd[k<<1|1];
    }
    void push_down(int k)
    {
    	if(!tag[k])return;
    	tag[k<<1]^=1,nd[k<<1].flip();
    	tag[k<<1|1]^=1,nd[k<<1|1].flip();
    	tag[k]=0;
    }
    void update(int k,int L,int R,int l,int r)
    {
    	if(L<=l&&r<=R)
    	{
    		tag[k]^=1,nd[k].flip();
    		return;
    	}
    	push_down(k);
    	int mid=(l+r)>>1;
    	if(L<=mid)update(k<<1,L,R,l,mid);
    	if(R>mid)update(k<<1|1,L,R,mid+1,r);
    	nd[k]=nd[k<<1]*nd[k<<1|1];
    }
    Matrix query(int k,int L,int R,int l,int r)
    {
    	if(L<=l&&r<=R)return nd[k];
    	push_down(k);
    	int mid=(l+r)>>1;
    	if(R<=mid)return query(k<<1,L,R,l,mid);
    	else if(L>mid)return query(k<<1|1,L,R,mid+1,r);
    	else return query(k<<1,L,R,l,mid)*query(k<<1|1,L,R,mid+1,r);
    }
    
    int main()
    {
    	A.resize(1,3);
    	A[1][1]=0,A[1][2]=0,A[1][3]=1;
    	int T,n,Q;
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d",&n,&Q);
    		scanf("%s",str+1);
    		build(1,1,n);
    		int op,x,y;
    		while(Q--)
    		{
    			scanf("%d%d%d",&op,&x,&y);
    			if(op==1)update(1,x,y,1,n);
    			else
    			{
    				Matrix res=A*query(1,x,y,1,n);
    				printf("%d
    ",(res[1][1]+res[1][2])%P);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    idea找不到或无法加载主类
    Scala核心编程_第09章 面向对象编程(高级特性)
    spring源码:学习线索
    Redis
    spring源码:Aware接口
    spring源码:核心组件(li)
    java socket编程
    spring源码:ApplicationContext的增强功能(li)
    spring源码:web容器启动
    spring源码:BeanPostProcessor(li)
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10189068.html
Copyright © 2011-2022 走看看