• COI 2020 Semafor(矩阵乘法+优化)


    COI 2020 Semafor

    题目大意

    • 给定一个初始显示 X X X M M M位的五段显示器,求 N N N次操作后显示为 i ( i ∈ [ 0 , 1 0 M ) ) i(iin[0,10^M)) i(i[0,10M))的方案数,需满足每 K K K次操作后显示的均是一个合法的数字。每次操作即改变显示器某一段的开关状态。
    • M ≤ 2 , N ≤ 1 0 15 Mle 2,Nle 10^{15} M2N1015

    题解

    • 看到多次操作后求方案数会想到矩乘,为了满足 K K K的限制,可以先把每操作 K K K次后的状态计算出来,如果不是合法的数的状态则忽略,再计算 N K frac{N}{K} KN 次合法的数之间的转移,最后再算上剩下 N mod ⁡ K Noperatorname{mod}K NmodK 次操作。
    • 计算一下复杂度,合法的数之间的转移最大是 1 0 2 3 ∗ log ⁡ N = 1 0 6 ∗ log ⁡ N {10^2}^3*log N = 10^6 * log N 1023logN=106logN,但前面每 K K K次所有状态之间的转移,当 M = 2 M=2 M=2时显示器有十段,状态压缩后大小为 2 10 = 1024 2^{10}=1024 210=1024,矩乘转移的复杂度一次就是 ( 2 10 ) 3 = 2 30 (2^{10})^3=2^{30} (210)3=230,显然需要改变做法。
    • 可以发现,当合法的两个数 x , y x,y x,y之间的转移,相当于把某些位取反,而剩下的不变,即异或上某数 k = x xor ⁡ y k=xoperatorname{xor}y k=xxory。那么对固定的 k k k,任意 x x x转移到 x xor ⁡ k xoperatorname{xor} k xxork的方案数都相等,所以转移矩阵就不需要维护 2 10 ∗ 2 10 2^{10}*2^{10} 210210大小,而只需记录不同的转移 k k k的值。
    • 转移时直接枚举 i i i j j j转移到 i xor ⁡ j ioperatorname{xor}j ixorj即可。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define md 1000000007
    #define N 1100
    #define M 110
    int p[10] = {10, 2, 9, 7, 18, 21, 12, 3, 29, 23};
    int vi[N];
    ll d[M], ans[M];
    ll f[M][M], g[M][M], c[M][M], cc[M][M];
    ll F[N], G[N], C[N];
    void ksm(ll x, int n) {
    	if(!x) {
    		for(int i = 0; i < n; i++)	
    			for(int j = 0; j < n; j++) f[i][j] = (i == j);
    	}
    	else {
    		ksm(x / 2, n);
    		for(int i = 0; i < n; i++)
    			for(int j = 0; j < n; j++) g[i][j] = 0;
    		for(int i = 0; i < n; i++)
    			for(int k = 0; k < n; k++) if(f[i][k])
    				for(int j = 0; j < n; j++) g[i][j] = (g[i][j] + f[i][k] * f[k][j]) % md;
    		for(int i = 0; i < n; i++)				
    			for(int j = 0; j < n; j++) f[i][j] = g[i][j];
    		if(x % 2) {
    			for(int i = 0; i < n; i++)
    				for(int j = 0; j < n; j++) g[i][j] = 0;
    			for(int i = 0; i < n; i++)
    				for(int k = 0; k < n; k++) if(c[i][k])
    					for(int j = 0; j < n; j++) g[i][j] = (g[i][j] + c[i][k] * f[k][j]) % md;
    			for(int i = 0; i < n; i++)				
    				for(int j = 0; j < n; j++) f[i][j] = g[i][j];
    		}
    	}
    }
    void Ksm(ll x, int n) {
    	if(!x) {
    		for(int i = 0; i < n; i++) F[i] = (i == 0);
    	}
    	else {
    		Ksm(x / 2, n);
    		for(int i = 0; i < n; i++) G[i] = 0;
    		for(int i = 0; i < n; i++) if(F[i])
    			for(int j = 0; j < n; j++) G[i ^ j] = (G[i ^ j] + F[i] * F[j]) % md;
    		for(int i = 0; i < n; i++) F[i] = G[i];
    		if(x % 2) {
    			for(int i = 0; i < n; i++) G[i] = 0;
    			for(int i = 0; i < n; i++) if(C[i])
    				for(int j = 0; j < n; j++) G[i ^ j] = (G[i ^ j] + C[i] * F[j]) % md;
    			for(int i = 0; i < n; i++) F[i] = G[i];
    		}
    	}
    }
    int main() {
    	ll n, K;
    	int m, X, i, j, k;
    	scanf("%d%lld%lld%d", &m, &n, &K, &X);
    	if(m == 1) {
    		for(i = 0; i < 5; i++) C[1 << i] = 1;
    		Ksm(K, 32);
    		memset(vi, 255, sizeof(vi));
    		for(i = 0; i < 10; i++) vi[p[i]] = i;
    		for(i = 0; i < 32; i++) if(vi[i] >= 0) 
    			for(j = 0; j < 32; j++) if(vi[j] >= 0) c[vi[i]][vi[j]] = F[i ^ j];
    		ksm(n / K, 10);
    		for(i = 0; i < 10; i++) d[i] = f[X][i];
    		Ksm(n % K, 32);
    		for(i = 0; i < 10; i++) 
    			for(j = 0; j < 10; j++) ans[j] = (ans[j] + d[i] * F[p[i] ^ p[j]]) % md;
    		for(i = 0; i < 10; i++) printf("%lld
    ", ans[i]);
    	}
    	else {
    		for(i = 0; i < 10; i++) C[1 << i] = 1;
    		Ksm(K, 1024);
    		memset(vi, 255, sizeof(vi));
    		for(i = 0; i < 10; i++) 
    			for(j = 0; j < 10; j++) vi[p[i] * 32 + p[j]] = i * 10 + j;
    		for(i = 0; i < 1024; i++) if(vi[i] >= 0) 
    			for(j = 0; j < 1024; j++) if(vi[j] >= 0) c[vi[i]][vi[j]] = F[i ^ j];
    		ksm(n / K, 100);
    		for(i = 0; i < 100; i++) d[i] = f[X][i];
    		Ksm(n % K, 1024);
    		for(i = 0; i < 100; i++) 
    			for(j = 0; j < 100; j++) ans[j] = (ans[j] + d[i] * F[(p[i / 10] * 32 + p[i % 10]) ^ (p[j / 10] * 32 + p[j % 10])]) % md;
    		for(i = 0; i < 100; i++) printf("%lld
    ", ans[i]);
    	} 
    	return 0;
    }
    
  • 相关阅读:
    缩点【洛谷P1262】 间谍网络
    模板-割点
    Tarjan缩点+LCA【洛谷P2416】 泡芙
    模拟赛 10-20考试记
    BFS【bzoj1667】: [Usaco2006 Oct]Cows on Skates滑旱冰的奶牛
    最短路【bzoj2464】: 中山市选[2009]小明的游戏
    linux /dev/mapper/centos-root 被占满
    Centos7中安装Mysql8并修改密码策略并远程连接
    Centos7中PHP编译安装mysqli扩展报错
    Linux中Composer 在安装依赖包与本地php版本不符问题
  • 原文地址:https://www.cnblogs.com/LZA119/p/14279500.html
Copyright © 2020-2023  润新知