zoukankan      html  css  js  c++  java
  • GDCPC2021 E

    题目

    source

    题解

    一眼看出是kmp+数位dp,然后就掉坑里了。。。
    数位dp显然时间会爆。观察数据范围,发现k长度最多为5,加上mod11的11个余数,最多有55个状态,可以使用矩阵快速幂。
    假设(f_{i,j})代表余数为i,当前匹配位置为j的结果。任意写出递推式,直接套矩阵快速幂。初始只有(f_{0,1}=1)(匹配状态从1开始),最终n次幂后将(f_{i,len+1})(f_{0,i})全部加起来就是答案了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 500 + 10;
    const int M = 998244353;
    typedef long long ll;
    #define endl '
    '
    typedef long long ll;
    
    struct mat {
    	ll arr[N][N];
    	int n;
    	mat(const ll mx[N][N], int n) : n(n) {
    		for(int i = 1; i <= n; i++) {
    			for(int j = 1; j <= n; j++) {
    				arr[i][j] = mx[i][j];
    			}
    		}
    	}
    	mat(int n) : n(n){
    		for(int i = 1; i <= n; i++) {
    			for(int j = 1; j <= n; j++) {
    				arr[i][j] = 0;
    			}
    		}
    	}
    	mat(const mat& m) : mat(m.arr, m.n){}
    	mat operator * (const mat &rhs) const {
    		ll res[N][N];
    		for(int i = 1; i <= n; i++) {
    			for(int j = 1; j <= n; j++) {
    				ll sum = 0;
    				for(int k = 1; k <= n; k++) {
    					sum += arr[i][k] * rhs.arr[k][j] % M;
    					sum %= M;
    				}
    				res[i][j] = sum;
    			}
    			
    		}
    		return mat(res, n);
    	}
    };
    
    int di[20];
    int nt[20];
    ll ans[N];
    int len;
    
    void getnext() {
        int i = 1, j = 0;
        nt[i] = j;
        while(i <= len) {
            if(j == 0 || di[i] == di[j]) {
                i++;
                j++;
                nt[i] = j;
            } else {
                j = nt[j];
            }
        }
    }
    
    int id(int st, int mod) {
    	return mod * 7 + st;	
    }
    
    mat qpow(mat A, int b) {
    	mat res(100);
    	for(int i = 1; i <= res.n; i++) res.arr[i][i] = 1;
    	while(b) {
    		if(b & 1) {
    			res = res * A;
    		}
    		A = A * A;
    		b = (b >> 1);
    	}
    	return res;
    }
    
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(0), cout.tie(0);
    	int t;
    	cin >> t;
    	while(t--) {
    		int n, k;
    		cin >> n >> k;
    		len = 0;
    		bool flag = true;
    		do{
    			if(k > 10 && (k % 10)) flag = false;
    			else if(k < 10 && k != 1) flag = false;
    			di[++len] = k % 10;
    			k /= 10;
    		} while(k);
    		if(n + 1 < len) flag = false;
    		getnext();
    		mat A(100);
    		auto &arr = A.arr;
    		for(int i = 1; i <= len + 1; i++) {
    			for(int j = 0; j < 11; j++) {
    				int id2 = id(i, j);
    				for(int k = 0; k <= 9; k++) {
    					int st = i, mod = j;
    					if(st < len + 1) {
    						while(st && k != di[st]) {
    							st = nt[st];
    						}
    						st++;
    					}
    					mod = (mod * 10 + k) % 11;
    					int id1 = id(st, mod);
    					arr[id1][id2]++;
    				}
    			}
    		}
    		mat res(qpow(A, n));
    		int tar = id(1, 0);
    		for(int i = 1; i <= 100; i++) {
    			ans[i] = res.arr[i][tar];
    		}
    		ll tans = 0;
    		for(int i = 0; i < 11; i++) {
    			tans += ans[id(len + 1, i)];
    			tans %= M;
    		}
    		for(int i = 1; i <= len; i++ ) {
    			tans += ans[id(i, 0)];
    			tans %= M;
    		}
    		cout << (tans + flag) % M << endl;
    	}
    }
    
  • 相关阅读:
    如何将网格式报表打印成其它样式
    拥有与实力不相称的脾气是种灾难——北漂18年(23)
    8.8.1 Optimizing Queries with EXPLAIN
    mysql 没有rowid 怎么实现根据rowid回表呢?
    secondary index
    8.5.5 Bulk Data Loading for InnoDB Tables 批量数据加载
    mysql 中key 指的是索引
    8.5.4 Optimizing InnoDB Redo Logging 优化InnoDB Redo 日志
    8.5.3 Optimizing InnoDB Read-Only Transactions 优化InnoDB 只读事务
    8.5.1 Optimizing Storage Layout for InnoDB Tables InnoDB表的存储布局优化
  • 原文地址:https://www.cnblogs.com/limil/p/14979260.html
Copyright © 2011-2022 走看看