[Sdoi2017]序列计数 [矩阵快速幂]

[Sdoi2017]序列计数

题意:长为\(n \le 10^9\)由不超过\(m \le 2 \cdot 10^7\)的正整数构成的和为\(t\le 100\)的倍数且至少有一个质数的序列个数


总-没有质数

裸矩阵快速幂,\(i \rightarrow (i+k)\mod t\)

但是构造矩阵m个数一个个试的话复杂度\(O(mt)\)

我们只管心\(\mod t\)之后的结果,处理处每个模t等价类的个数用它来构造矩阵就好了。我是zz

注意卡内存,存质数的数组可以小一点

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <ctime>
using namespace std;
const int N=2e7+5, mo=20170408;
typedef long long ll;
inline int read() {
	char c=getchar(); int x=0, f=1;
	while(c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
	while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
	return x*f;
}

int n, m, t;
int p[2000000], notp[N], c1[105], c2[105];
void sieve(int n) {
	notp[1]=1;
	for(int i=2; i<=n; i++) { //printf("i %d\n",i);
		if(!notp[i]) p[++p[0]]=i;
		for(int j=1; j<=p[0] && i*p[j]<=n; j++) { //printf("j %d\n",p[j]);
			notp[ i*p[j] ]=1;
			if(i % p[j] == 0) break;
		}
	}
	for(int i=1; i<=n; i++) c1[ i%t ]++, c2[ i%t ] += notp[i];
}

inline void mod(ll &x) {if(x>=mo) x-=mo;}

struct meow {
	ll a[101][101];
	meow() {memset(a, 0, sizeof(a));}
	ll* operator [](int x) {return a[x];}
	void ini() {for(int i=0; i<t; i++) a[i][i]=1;}
}g, a;

meow operator *(meow a, meow b) {
	meow c;
	for(int i=0; i<t; i++)
		for(int k=0; k<t; k++)
			for(int j=0; j<t; j++)
				mod(c[i][j] += a[i][k] * b[k][j] %mo);
	return c;
}
meow operator ^(meow a, int b) {
	meow ans; ans.ini();
	for(; b; b>>=1, a=a*a)
		if(b&1) ans=ans*a;
	return ans;
}

void build1() {
	for(int i=0; i<t; i++)
		for(int j=0; j<t; j++) g[i][ (i + j)%t ] += c1[j];
}
void build2() { 
	a = meow(); g = meow();
	for(int i=0; i<t; i++)
		for(int j=0; j<t; j++) g[i][ (i + j)%t ] += c2[j];
}
int main() {
	freopen("count.in", "r", stdin);
	freopen("count.out", "w", stdout);
	n=read(); m=read(); t=read();
	sieve(m);
	
	build1();
	a[0][0]=1; a = (g^n) * a;
	ll ans = a[0][0];  
	
	build2();
	a[0][0]=1; a = (g^n) * a;
	ans = (ans - a[0][0] + mo) % mo;
	
	cout << ans;
}

posted @ 2017-04-12 16:16  Candy?  阅读(320)  评论(0编辑  收藏  举报