JZOJ6915. 显示器(display)

题目大意

解题思路

第一部分:
考虑一个k步的转移,即从一个m位整数转移到另一个,那么这个东西可以通过O(25mlogk)的时间通过倍增优化dp求出.
具体地,设f2i,S表示改变了2i次灯管的状态能够到达灯管的状态为S的方案数, 那么一次转移实质上是一次异或卷积. 由于不会给了4秒,所以不用FWT,直接暴力卷积,倍增优化即可.

当求出了这个东西之后, 整个n步的转移就被分割成了nk次长度为k的转移和一次长度为nmodk的转移.

对于前面的一部分,即第二部分,使用矩阵快速幂, 在O((10m)3lognk)的时间内解决.
具体地,利用前面dp的结果可以构造出初始矩阵. 一次矩阵乘法也相当于一次转移. 不再细说.

对于后面的一部分,即第三部分, 可以与第一部分相类似的方法求解.

#include <cstdio>
#include <cstring>
#define N 110
#define ll long long
#define rg register
#define MOD 1000000007
#define init(a, b) memset(a, b, sizeof(a))
#define fo(i, a, b) for(int i = (a); i <= (b); ++i)
#define fd(i, a, b) for(int i = (a); i >= (b); --i)
using namespace std;
int m, x, p[3] = {1, 9, 99}, q[3] = {1, 31, 1023}, pr[100] = {10, 2, 9, 7, 18, 21, 12, 3, 29, 23}, w[1024];
ll n, k;
struct Mat
{
	int a[N][N];
	Mat(){init(a, 0);}
	int* operator[] (const int x) {return a[x];}
	Mat operator*(Mat y) const
	{
		Mat z;
		fo(i, 0, p[m])
			fo(k, 0, p[m])
			{
				rg int t = a[i][k];
				if(!t)	continue ;
				fo(j, 0, p[m])
					z[i][j] = (z[i][j] + 1ll * a[i][k] * y[k][j]) % MOD;
			}
		return z;
	}
}ans1, p1;
struct Poly
{
	int a[1 << 10];
	Poly(){init(a, 0);}
	int& operator[](const int x){return a[x];}
	Poly operator*(Poly y) const
	{
		Poly z;
		fo(i, 0, q[m])
			fo(j, 0, q[m])
				z[i ^ j] = (z[i ^ j] + 1ll * a[i] * y[j]) % MOD;
		return z;
	}
}ans2, p2;
template<typename T>
inline void qpow(T &p, T a, ll b){for(; b; b >>= 1, a = a * a)	b & 1 && (p = p * a, 1);}
inline void pre()
{
	if(m == 2)
	{
		fo(i, 10, 99)	pr[i] = pr[i % 10] + (pr[i / 10] << 5);
		fo(i, 0, 9)	pr[i] += 10 << 5;
	}
	fo(i, 0, q[m])	w[i] = -1;
	fo(i, 0, p[m])	w[pr[i]] = i;
	fo(i, 1, m * 5)	p2[1 << (i - 1)] = 1;
}
int main()
{
	freopen("display.in", "r", stdin);
	freopen("display.out", "w", stdout);
	scanf("%d %lld %lld %d", &m, &n, &k, &x);
	pre();
	ans2[0] = 1; qpow(ans2, p2, k);
	fo(i, 0, p[m])	fo(j, 0, p[m])	p1[i][j] = ans2[pr[i] ^ pr[j]];
	fo(i, 0, q[m])
		if(w[i ^ pr[x]] >= 0)
			ans1[0][w[i ^ pr[x]]] = ans2[i];
	qpow(ans1, p1, n / k - 1);
	fo(i, 0, q[m])	ans2[i] = 0;
	fo(i, 0, p[m])	ans2[pr[i]] = ans1[0][i];
	qpow(ans2, p2, n % k);
	fo(i, 0, p[m])	printf("%d\n", ans2[pr[i]]);
	return 0;
}
posted @   Martin_MHT  阅读(111)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示