• 围圈圈


    Description

    jzj都成年两个多月了,为了重拾自己的童心,jzj跑到幼儿园去当小老师啦~

    幼儿园里一共有无数个不同性别不同高矮的小盆友,现在jzj要带着小朋友们做游戏,首先要把小盆友们排成一个圈,一轮游戏只能有N个小盆友参加。每个小盆友的性别是不同的,高矮也是不一样的(即每个小盆友的信息可以用两个参数来衡量,一种是男女,一种是高矮,一个小盆友只能或男或女,或高或矮……),当两个小盆友性别不一样高矮也不一样的时候,他们是不愿意手拉手排在相邻的位置的。现在jzj想知道一共有多少种方法把小盆友围成一个大小为N的圈圈。(考虑绝对位置,也就是如果这个圈圈逆时针或者顺时针转一个单位也被认为是不同的排法。)

    p.s由于不同性别不同高矮的小盆友有无数个,所以排位置的时候你可以决定每个位置小盆友的性别和高矮。

    Analysis

    递推

    先不管数据量,分析一下这道题的状态转移方法。对于n个小盆友围在一起,将其看作一条队列,针对对头和队尾的不同情况进行分析。

    1. 对头和队尾完全相同,可以由(n-1,1)与(n-1,2)进行推演
    2. 对头和队尾有一个元素相同,也可以由(n-1,1)与(n-1,2)推演,但是对于n-1个小盆友队头队尾无法匹配时,可以再来一个小盆友作为媒介进行连接

    所以就有了第三种
    3. 对头和队尾无法匹配,可以由(n-1,2)和(n-1,3)推演而来。

    dp[i][1]=dp[i-1][1]+dp[i-1][2]
    
    dp[i][2]=2*dp[i-1][1]+dp[i-1][2]+2*dp[i-1][3]
    
    dp[i][3]=dp[i-1][2]+dp[i-1][3]
    

    复杂度O(n)

    找规律

    显然,对于n<=10^ 100,递推是没有指望的。打出来1~20的数据后发现,n为奇数时方案数为n^ 3 +1,偶数时为n^ 3 +4,所以打一个大整数快速幂就过了。

    复杂度O(logn)

    Code

    #include <bits/stdc++.h>
    #define mo 20101031
    
    struct bigint{
    	int len,num[510];
    	bigint operator = (bigint eq){
    		len=eq.len;
    		memset(num,0,sizeof(num));
    		for(int i=0;i<len;i++)
    			num[i]=eq.num[i];
    		return *this;
    	}
    	bigint operator = (std::string eq){
    		len=eq.size();
    		memset(num,0,sizeof(num));
    		for(int i=0;i<len;i++)
    			num[i]=eq[len-i-1]-'0';
    		return *this;
    	}
    	bool parity(){
    		return num[0]&1;
    	}
    	bigint operator / (int dv){
    		bigint ans;
    		ans.len=len;
    		memset(ans.num,0,sizeof(ans.num));
    		int bc=0;
    		for(int i=len-1;i>=0;i--){
    			bc=bc*10+num[i];
    			if(bc>=dv)ans.num[i]=bc/dv,bc%=dv;
    		}
    		while(ans.len-1&&!ans.num[ans.len-1])ans.len--;
    		return ans;
    	}
    	bigint operator /= (int dv){
    		return *this=*this/dv;
    	}
    	friend std::ostream& operator << (std::ostream& out,bigint ans){
    		for(int i=ans.len-1;i+1;i--)
    			out<<ans.num[i];
    		return out;
    	}
    };
    
    long long ans,mt;
    bigint n;
    
    int main(){
    	freopen("circle.in","r",stdin);
    	freopen("circle.out","w",stdout);
    	std::string get;
    	std::cin>>get;
    	n=get;
    	ans=1;
    	mt=3;
    	int add=n.parity()?1:3;
    	while(n.len>1||n.num[0]>0){
    		if(n.parity())ans=ans*mt%mo;
    		n/=2;
    		mt=mt*mt%mo;
    	}
    	std::cout<<(ans+add)%mo<<std::endl;
    	return 0;
    }
    

    矩阵加速

    当然找规律也不是万能的,所以可以利用我们得出的递推式进行矩阵加速。

    要掌握找递推式再加速这一思维体系。

    Code O(9·logn)

    ##include <bits/stdc++.h>
    const int N=11,Mod=20101031;
    typedef long long int64;
    struct bigint{
    	int l,s[110];
    	void clear(){
    		l=0;
    		memset(s,0,sizeof(s));
    	}
    	void minus(){
    		for(int i=0;i<l;i++){
    			s[i]--;
    			if(s[i]<0)s[i]+=10;
    			else break;
    		}
    	}
    	bool exist(){
    		return (l-1)||(s[0]);
    	}
    	bool parity(){
    		return s[0]&1;
    	}
    	bigint operator = (std::string x){
    		clear();
    		l=x.size();
    		for(int i=0;i<l;i++)
    			s[i]=x[l-i-1]-'0';
    		return *this;
    	}
    	bigint operator / (int x){
    		bigint y;
    		y.clear();
    		y.l=l;
    		int bc=0;
    		for(int i=l-1;i>=0;i--){
    			bc=bc*10+s[i];
    			if(bc>=x)y.s[i]=bc/x,bc%=x;
    		}
    		while(y.l-1&&!y.s[y.l-1])y.l--;
    		return y;
    	}
    	bigint operator /= (int x){
    		return *this=*this/x;
    	}
    	friend std::ostream& operator << (std::ostream& out,bigint ans){
    		for(int i=ans.l-1;i+1;i--)
    			out<<ans.s[i];
    		return out;
    	}
    };
    struct Matrix{
    	int h,l;
    	int64 s[N][N];
    	void clear(){
    		h=l=0;
    		memset(s,0,sizeof(s));
    	}
    	Matrix operator + (Matrix x){
    		Matrix y;
    		y.clear();
    		y.h=h,y.l=l;
    		for(int i=0;i<h;i++)
    			for(int j=0;j<l;j++)
    				y.s[i][j]=(s[i][j]+x.s[i][j])%Mod;
    		return y;
    	}
    	Matrix operator * (Matrix x){
    		Matrix y;
    		y.clear();
    		y.h=h,y.l=x.l;
    		for(int i=0;i<h;i++)
    			for(int j=0;j<x.l;j++)
    				for(int k=0;k<l;k++)
    					y.s[i][j]=(y.s[i][j]+s[i][k]*x.s[k][j])%Mod;
    		return y;
    	}
    }ans,cal,E;
    void init(){
    	ans.clear();
    	ans.h=1,ans.l=3;
    	ans.s[0][0]=4,ans.s[0][1]=0,ans.s[0][2]=0;
    	cal.clear();
    	cal.h=cal.l=3;
    	cal.s[0][0]=cal.s[1][0]=cal.s[1][1]=cal.s[1][2]=cal.s[2][2]=1;
    	cal.s[0][1]=cal.s[2][1]=2;
    	E.clear();
    	E.h=E.l=3;
    	for(int i=0;i<3;i++)
    		E.s[i][i]=1;
    }
    Matrix fast_pow(bigint k){
    	Matrix a,b;
    	a=cal,b=E;
    	while(k.exist()){
    		if(k.parity())b=b*a;
    		k/=2;
    		a=a*a;
    	}
    	return b;
    }
    int main(){
    	//freopen("circle.in","r",stdin);
    	//freopen("circle.out","w",stdout);
    	bigint k;
    	std::string get;
    	std::cin>>get;
    	k=get;
    	k.minus();
    	init();
    	ans=ans*fast_pow(k);
    	printf("%lld
    ",(ans.s[0][0]+ans.s[0][1])%Mod);
    	return 0;
    }
    
  • 相关阅读:
    第一次团队作业
    第二次结对作业
    动态代理与AOP
    笔试题
    java并发面试题(带答案)
    线程问题——同步和死锁
    java线程的方法
    java实现多线程的方法
    使用java闭锁实现并发
    Java多线程——同步问题
  • 原文地址:https://www.cnblogs.com/qswx/p/9494982.html
Copyright © 2020-2023  润新知