codeforces 497E Subsequences Return

codeforces 497E Subsequences Return

想法

做完这题,学了一些东西。
1、求一个串不同子序列个数的两种方法。解一 解二
2、这道题 \(n\) 很大,很容易想到矩阵加速,但是之前遇到的矩阵的题目,矩阵都是相同的,这题的矩阵虽然不同,但是至多 \(k\) 个,并且出现规律与 \(0\) ~ \(n-1\)\(k\) 进制形态有关。题解中基于这点进行的优化和 \(dp\) 的思想又很像。

代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define sz(x) (int)x.size()
#define de(x) cout<< #x<<" = "<<x<<endl
#define dd(x) cout<< #x<<" = "<<x<<" "
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

const int MOD=1e9+7, N=33;

ll n;
int k;
vi dig;

inline void upd(ll &a, ll b) {
	a+=b;
	if(a>=MOD) a-=MOD;
}

struct M {
	ll a[N][N];
	M() {memset(a,0,sizeof(a));}
	void Set() {rep(i,0,k+1) a[i][i]=1;}
	M operator * (const M &c) const {
		M res;
		rep(i,0,k+1) rep(j,0,k+1) rep(_,0,k+1) upd(res.a[i][j], a[i][_]*c.a[_][j]%MOD);
		return res;
	}
}A[N<<1][N], S[N<<1][N], P[N<<1][N], ans;

int main() {
	scanf("%lld%d",&n,&k);
	rep(i,0,k) {
		A[0][i].Set();
		rep(j,0,k+1) A[0][i].a[i][j]=1;
	}
	ll len=k;
	for(int i=1;len<=n;++i, len*=k) {
		S[i-1][k-1]=A[i-1][k-1];
		for(int j=k-2; ~j; --j) S[i-1][j]=A[i-1][j]*S[i-1][j+1];
		P[i-1][0]=A[i-1][0];
		rep(j,1,k) P[i-1][j]=P[i-1][j-1]*A[i-1][j];
		A[i][0]=S[i-1][0];
		rep(j,1,k) A[i][j]=S[i-1][j]*P[i-1][j-1];
	}
	while(n) {
		dig.pb(n%k);
		n/=k;
	}
	int s=0;
	ans.Set();
	for(int i=sz(dig)-1;~i;--i) {
		rep(j,0,dig[i]) {
			ans=ans*A[i][(j+s)%k];
		}
		s=(s+dig[i])%k;
	}
	ll res=1;
	rep(i,0,k) upd(res, ans.a[i][k]);
	printf("%lld\n",res);
	return 0;
}

posted @ 2018-04-15 17:22  yuanyuan-97  阅读(273)  评论(0编辑  收藏  举报