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;
    }
    
  • 相关阅读:
    83. Remove Duplicates from Sorted List
    35. Search Insert Position
    96. Unique Binary Search Trees
    94. Binary Tree Inorder Traversal
    117. Populating Next Right Pointers in Each Node II
    116. Populating Next Right Pointers in Each Node
    111. Minimum Depth of Binary Tree
    169. Majority Element
    171. Excel Sheet Column Number
    190. Reverse Bits
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10189068.html
Copyright © 2011-2022 走看看