JZOJ 4533. 【清华夏令营2016模拟5.31】图森破(动态规划+容斥+mobius反演+杜教筛)

Description:

小火车励志成为一名辣鸡出题人,但是要成为一名辣鸡出题人,代码必须跑得比谁都快,这样就能把他们都卡常数了!为了锻炼自己,他找到了一位长者——罗长者,罗长者说:“你啊,toosimple!不要想弄一个大新闻,说现在已经‘钦定’了,然后把我批评一番。”小火车坐在高高的骨灰旁边,听长者讲那钦定的事情。
如果一个n位数X(可以有前导0)对所有的k(1<=k<n)都满足X10k mod 10n>X,长者就会钦定这个X,然后长者会产生n2的愉悦度。长者会指定一个n,然后钦定满足条件的1位数,2位数,...,n位数。求长者的愉悦度之和,答案模258280327(2317+1,一个质数)。

https://gmoj.net/senior/#main/show/4533

题解:

考虑一个串,如果它没有循环同构串和它相同,那么它的最小循环同构串就是一个合法的答案。

(f[n])为长度为(n)的没有循环同构串和自己相同的串个数,那么(f[n]/n)就是长度(n)时的答案。

不难得到dp:
(f[n]=10^n-sum_{d|n~and~d eq n} f[d])

直接统计(10^{...})的贡献,不难得到:
(f[n]=sum_{d|n}10^d*mu(n/d))

或者用mobius反演推出(f)

(g[n])表示长度为(n)可能循环的串数,(g[n]=10^n=sum_{d|n}f[d])
所以(f[n]=sum_{d|n}g[d]*mu(n/d)=sum_{d|n}10^d*mu(n/d))

那么
(Ans=sum_{i=1}^n i*sum_{j|i}10^j*mu(i/j))
(=sum_{i=1}^n mu(i)*i sum_{j=1}^{n/i} 10^j*j)

杜教筛处理(mu(i)*i)的前缀和,后面是高中数列题。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("
")
using namespace std;

const int mo = 258280327;

ll ksm(ll x, ll y) {
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

const ll ni2 = ksm(2, mo - 2);

const int N = 1e6 + 5;

int bz[N], p[N], p0, mu[N];
ll s[N];

void sieve(int n) {
	mu[1] = 1;
	fo(i, 2, n) {
		if(!bz[i]) p[++ p0] = i, mu[i] = -1;
		for(int j = 1; i * p[j] <= n; j ++) {
			int k = i * p[j] % mo;
			bz[k] = 1;
			if(i % p[j] == 0) {
				mu[k] = 0; break;
			}
			mu[k] = -mu[i];
		}
	}
	fo(i, 1, n) s[i] = (s[i - 1] + mu[i] * i) % mo;
}

ll n;

ll cn1(ll x) {
	x %= mo;
	return x * (x + 1) % mo * ni2 % mo;
}

const ll ni9 = ksm(9, mo - 2);

ll calc(ll x) {
	ll s = (ksm(10, x + 1) - 10) * ni9 - ksm(10, x + 1) * (x % mo);
	s = (-s % mo + mo) * ni9 % mo;
	return s;
}

const int M = 1960817;

struct hash {
	ll h[M], f[M];
	int fi[M], nt[M], tot;
	ll &operator [] (ll n) {
		int y = n % M;
		for(int p = fi[y]; p; p = nt[p])
			if(h[p] == n) return f[p];
		nt[++ tot] = fi[y], fi[y] = tot, h[tot] = n;
		return f[tot];
	}
	int find(ll n) {
		int y = n % M;
		for(int p = fi[y]; p; p = nt[p])
			if(h[p] == n) return 1;
		return 0;
	}
} h;

ll dg(ll n) {
	if(n <= 1e6) return s[n];
	if(h.find(n)) return h[n];
	ll s = 1;
	for(ll i = 2, j; i <= n; i = j + 1) {
		j = n / (n / i);
		s = (s - (cn1(j) - cn1(i - 1)) * dg(n / i)) % mo;
	}
	s = (s % mo + mo) % mo;
	return h[n] = s;
}

int main() {
	sieve(1e6);
	scanf("%lld", &n);
	ll ans = 0;
	for(ll i = 1, j; i <= n; i = j + 1) {
		j = n / (n / i);
		ans = (ans + (dg(j) - dg(i - 1)) * calc(n / i))	% mo;
	}
	ans = (ans % mo + mo) % mo;
	pp("%lld
", ans);
}
原文地址:https://www.cnblogs.com/coldchair/p/12938213.html