• P1357 花园


    算法

    我们发现题目中(m < 5)很小

    所以我们可以使用二进制压缩。

    我们用(1)来表示(C)(0)表示(P),我们压缩的是当前这个状态的最后(m)位的状态 比如后(m)位是(CCPP)则压缩为((1100)_2)这个数

    接下来我们讨论一下状态如何转移

    首先好像我对于一个状态的转移和其他题解的方法不大相同。
    我对于一个状态向其他状态的转移是这样的:

    now_0 = (now << 1) & ((1 << m) - 1);
    now_1 = (now << 1) & ((1 << m) - 1) + 1;
    
    

    这个转移可能是更加符合题目的意思吧。
    举个栗子:

    就如题目中所给的例子 (m = 2 k = 1)

    我们就有如下的转移:

    (00 -> 01)

    (00 -> 00)

    (10 -> 01)

    (10 -> 00)

    (01 -> 10)

    我们可以发现从现在这个状态([i ,i + m])([i + 1,i + m + 1])的状态转移相当把([i,i + m]) 这个状态的第一个数字挤出去,再在最后一位填上新的数字,我们设(f[i][j])为第(i)位向后(m)位状态为(j)的方案数。

    那么我们就知道如果我们枚举([0,m])的状态 则我们的答案是(f[n + 1][j] j)(2)进制下(1)的个数小于(k)。我们还发现每个(f[i][j])都从(f[i - 1][j])达到,所以我们可以用上滚动数组 这样能够做到(70pts)

    但我们可是冲着(100pts)去的啊 区区(70pts)

    我们可以预处理出这个一个矩阵,类似于邻接矩阵,将(i ->j)这个一个关系,当成一条边存入,这个过程可以使用(dfs)。然后我们要做的是转移,就转换成了经典的图上求到达每个点的方案数了,类似于P2886 [USACO07NOV]Cow Relays G这个用矩阵快速幂的题目(建议先做这个题),我们本题也可以使用矩阵快速幂来进行加速。

    最后上代码啦

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define MOD 1000000007 
    
    using namespace std;
    
    ll n,m,k,fin = 0;
    
    bool vis[(1 << 6) + 1][(1 << 6) + 1];
    
    struct map{
    	ll f[(1 << 6) + 1][(1 << 6) + 1]; 
    	map(){
    		memset(f,0,sizeof(f));
    	}
    }a,ans;
    
    void dfs(ll now,ll last){
    	if(vis[last][now])
    	return;
    	if(now >= (1 << m))
    	return;
    	vis[last][now] = 1;
    	a.f[last][now] = 1;
    	ll z = now;
    	now = (now << 1) & ((1 << m) - 1);
    	if(__builtin_popcount(now) >= k)
    	dfs(now,z);
    	else{
    		dfs(now + 1,z);
    		dfs(now,z);
    	}
    }
    
    map operator * (const map &x,const map &y){
    	map z;
    	for(ll i = 0;i <= (1 << m) - 1;i ++)
    	for(ll j = 0;j <= (1 << m) - 1;j ++)
    	for(ll k = 0;k <= (1 << m) - 1;k ++)	
    	z.f[i][j] = (z.f[i][j] + (1ll * x.f[i][k] * y.f[k][j]) % MOD) % MOD;
    	return z;
    } 
    void quick(ll k){
    	ans = a;
    	k -= 1;
    	while(k){
    		if(k & 1) ans = ans * a;
    		a = a * a;
    		k >>= 1;
    	}
    }
    int main(){
    	scanf("%lld%lld%lld",&n,&m,&k);
        dfs(0,0);
        quick(n);
    	for (int i = 0; i < (1 << m) - 1; ++i) {
    		fin = (fin + ans.f[i][i]) % MOD;
    	}
        cout<<fin;
    } 
    
    
  • 相关阅读:
    MySQL crash-safe replication
    Innodb单表数据物理恢复
    从MySQL全库备份中恢复一个库和一张表
    mysqldump中master-data和dump-slave的区别
    mysqldump常用参数
    mysqldump --single-transaction 和--lock-tables参数详解
    CF757E Bash Plays with Functions
    通过binlog日志统计dml语句,找出操作频繁的表
    [SDOI2015]约数个数和
    常用binlog日志操作命令
  • 原文地址:https://www.cnblogs.com/dixiao/p/13849461.html
Copyright © 2020-2023  润新知