zoukankan      html  css  js  c++  java
  • [状压矩阵优化DP]花园

    题目

    题解

    我就是个辣鸡,状压都没看出来,只会打dfs
    对于m<=5,肯定考虑状压
    令C为1,P为0
    那么二进制状态最多也就11111,十进制的31,数组不大,可以过80
    令dp[i][s]表示序列长度为i,最后m位状态为s的方案数,肯定可以通过dp[i][k]转移过来
    至于k,s能否进行转移,我们先进行dfs预处理出所有合法情况,且两个状态能否转移。用vis数组标记。
    之后枚举起点即前m个的情况,进行dp即可。
    需要注意的是这个序列是环形的,因而我们需要多搞一个m,那么最后我们回到了初始的状态
    朴素DP代码如下

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<set>
    #include<ctime>
    using namespace std;
    const int mod = 1e9 + 7;
    long long n,dp[100005][35],ans;
    int m,k,a[6],sum[10];
    bool vis[65][65],ok[65];
    void check(){
    	int x = 0,y = 0;
    	for (int i = 1;i <= m;i ++)
    		x = x * 2 + a[i];
    	for (int i = 2;i <= m + 1;i ++)
    		y = y * 2 + a[i];
    	for (int i = 1;i <= m + 1;i ++)
    		sum[i] = sum[i - 1] + a[i];
    	for (int i = m;i <= m + 1;i ++)
    		if (sum[i] - sum[i - m] > k)
    			return ;
    	vis[x][y] = 1,ok[x] = 1,ok[y] = 1;
    }
    void work(int x){
    	memset(dp,0,sizeof(dp));
    	dp[m][x] = 1;
    	for (int i = m + 1;i <= n + m;i ++)
    		for (int j = 0;j < (1 << m);j ++)
    			for (int k = 0;k < (1 << m);k ++)
    				if (vis[j][k])
    					dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod;
    	ans = (ans + dp[n + m][x]) % mod;
    }
    void dfs(int step){
    	if (step > m + 1){
    		check();
    		return ;
    	}
    	a[step] = 1;
    	dfs(step + 1);
    	a[step] = 0;
    	dfs(step + 1);
    }
    int main(){
    	scanf ("%lld%d%d",&n,&m,&k);
    	dfs(1);
    	for (int i = 0;i < (1 << m);i ++)
    		if (ok[i])
    			work(i);
    	printf("%lld
    ",ans);
    }
    

    但是n太大了,我们搞不动,但我们会发现对于每一个状态,更新它的状态其实是一定的,且每一个状态都更新了n次。因而我们将vis数组自乘n次,加上能回到初始状态的方案数即可。是一个矩阵优化DP的做法

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<set>
    #include<ctime>
    using namespace std;
    const int mod = 1e9 + 7;
    struct matrix{
    	long long x[65][65];
    	matrix(){
    		memset(x,0,sizeof(x));
    	}
    	matrix operator * (const matrix &rhs)const {
    		matrix tmp;
    		for (int i = 0;i <= 31;i ++)
    			for (int j = 0;j <= 31;j ++)
    				for (int k = 0;k <= 31;k ++)
    					tmp.x[i][j] = (tmp.x[i][j] + (x[i][k] * rhs.x[k][j]) % mod) % mod;
    		return tmp;
    	}
    }vis;
    long long n,ans;
    int m,k,a[6],sum[10];
    bool ok[65];
    void check(){
    	int x = 0,y = 0;
    	for (int i = 1;i <= m;i ++)
    		x = x * 2 + a[i];
    	for (int i = 2;i <= m + 1;i ++)
    		y = y * 2 + a[i];
    	for (int i = 1;i <= m + 1;i ++)
    		sum[i] = sum[i - 1] + a[i];
    	for (int i = m;i <= m + 1;i ++)
    		if (sum[i] - sum[i - m] > k)
    			return ;
    	vis.x[x][y] = 1,ok[x] = 1,ok[y] = 1;
    }
    /*void work(int x){
    	memset(dp,0,sizeof(dp));
    	dp[m][x] = 1;
    	for (int i = m + 1;i <= n + m;i ++)
    		for (int j = 0;j < (1 << m);j ++)
    			for (int k = 0;k < (1 << m);k ++)
    				if (vis[j][k])
    					dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod;
    	ans = (ans + dp[n + m][x]) % mod;
    }*/
    void dfs(int step){
    	if (step > m + 1){
    		check();
    		return ;
    	}
    	a[step] = 1;
    	dfs(step + 1);
    	a[step] = 0;
    	dfs(step + 1);
    }
    matrix qkpow(matrix x,long long y){
    	matrix ans;
    	for (int i = 0;i <= 31;i ++)
    		ans.x[i][i] = 1;
    	while (y){
    		if (y & 1)
    			ans = ans * x;
    		x = x * x;
    		y /= 2;
    	}
    	return ans;
    }
    int main(){
    	scanf ("%lld%d%d",&n,&m,&k);
    	dfs(1);
    	vis = qkpow(vis,n);
    	for (int i = 0;i < (1 << m);i ++)
    		if (ok[i])
    			ans = (ans + vis.x[i][i]) % mod;
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    Android Studio 2.2以上支持了Cmake的配置JNI的相关参数
    Unable to instantiate receiver xxx.receiver.NetworkReceiver异常
    关于imageview matrix
    Android NDK开发 JNI操作java构造方法,普通方法,静态方法(七)
    COOKIE和SESSION的区别
    Android NetworkInterface 的 name
    Android ROM资源文件存放位置
    selinux
    当WebView运行在特权进程时抛出安全异常,Hook方式解决方案(包含对Android 8.0的处理)
    Android判断当前是否在主线程
  • 原文地址:https://www.cnblogs.com/lover-fucker/p/13566647.html
Copyright © 2011-2022 走看看