在这片梦想之地,不堪回首的过去像泡沫一样散去,不愿|

PassName

园龄:3年粉丝:32关注:16

照亮数学的七道光芒 T1-4

照亮数学的七道光芒

勇气

对于第 k 次攻击,其攻击力为:

ak=x2k22k2

对于这个题,显然就是找最小的 k 使满足这个式子

x2k22k22n

2 为底取对数,有

2klog2x(2k2)n

2kn2log2x1

如果 x2n 答案直接就是零,如果 x=2n>2 则无解。

signed main()
{
    cin >> x >> n;
	if (x == 2 && n > 2) 
	{
		cout << "inf";
		return 0;
	} 
	else if (x == 2 && n == 2) 
	{
		cout << 1;
		return 0;
	} 
	else if (n == 1) 
	{
		cout << 0;
		return 0;
	}
	int times = (ceil)(n - 2) / (log2(x) - 1);
	int check = 1;
	if (check >= times)
	{
		cout << 0;
		return 0;
	}
	for (rint i = 1; ; i++)
	{
		check *= 2;
		if (check >= times) 
		{
			cout << i;
			return 0;
		}
	}
}

奉献

仔细读题寻找性质,当且仅当 gcd(a,b)=1 时,它没有在之前被填写过

将朴素式子列出来:

i=1nj=1i(dilog2di+k=1nidk)×check(gcd(i,j))

其中 check(x)bool 型,当且仅当 x=1 时为 1,否则为 0

将式子进行转化:

i=1n(dilog2di+k=1nidk)j=1icheck(gcd(i,j))

即为:

i=1n(dilog2di+k=1nidk)×φ(i)

这些东西我们都是会求的,这个题最后一个地方,在于 di 不能直接求,差分一下。

void init() 
{
	v[1] = phi[1] = 1;
	for (rint i = 2; i <= n; i++) 
	{
		if (!v[i]) 
		{
			prime[++cnt] = i;
			phi[i] = i - 1;
		}
		for (rint j = 1; prime[j] * i <= n && j <= cnt; j++) 
		{
			v[i * prime[j]] = 1;
			if (!(i % prime[j])) 
			{
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			phi[i * prime[j]] = phi[i] * phi[prime[j]];
		}
	}
}

signed main() 
{
	cin >> n;
	init();
	for (rint i = 1; i <= n; i++) 
	{
		d[i] = 1 + d[i / 10];
		s[i] = s[i - 1] + d[i];
	}
	for (rint i = 1; i <= n; i++) 
	{
		double sum = ((double)log2(d[i]) * d[i] + s[n / i]) * phi[i];
		ans += sum;
	}
	cout << fixed << setprecision(10) << ans << endl;
	return 0;
}

高洁

前置知识 The Sum of the k-th Powers

(i=1nik)mod(109+7)

答案是一个 k+1 次多项式,考虑找 k+2 个值带进去拉格朗日插值

n+1 组点值(xi,yi),有 n 次多项式 f 的拉格朗日插值:

f(x)=i=0nyijixxjxixj

复杂度为 O(n2).

在此题中把 1k+2 带入,有对于每个 i,分母是1 乘到 i1 再乘上 1 乘到 ik2,这可以预处理阶乘 O(1) 处理。分子可以预处理前后缀积来 O(1) 得到

复杂度为 O(n)

signed main() 
{
	cin >> n >> k;
	pl[0] = pr[k + 3] = fac[0] = 1;
	
	for (rint i = 1; i <= k + 2; i++) pl[i] = pl[i - 1] * (n - i) % mod;
	for (rint i = k + 2; i >= 1; i--) pr[i] = pr[i + 1] * (n - i) % mod;
	for (rint i = 1; i <= k + 2; i++) fac[i] = fac[i - 1] * i % mod;
	for (rint i = 1; i <= k + 2; i++) 
	{
		y = (y + qpow(i, k)) % mod;
		int a = pl[i - 1] * pr[i + 1] % mod;
		int b = fac[i - 1] * ((k - i) & 1 ? -1 : 1) * fac[k + 2 - i] % mod;
		ans = (ans + y * a % mod * qpow(b, mod - 2) % mod) % mod;
	}
	cout << (ans + mod) % mod << endl;
	return 0;
}

在看我们的原题

v(i) 只和 gcd(i,d) 有关。枚举 d 的因数,考虑它的倍数对答案的贡献。

结果为 idj=1n/i(ij)v(i)[gcd(j,d/i)==1]

整理得:

idiv(i)+1j=1n/ijv(i)+1[gcd(j,d/i)==1]=idiv(i)+1j=1n/ijv(i)+1pi,jμ(p)=idiv(i)+1pdiμ(p)j=1n/i/pjv(i)+1

v(i)d 的所有质因子在 d 中出现次数与在 i 中出现次数的商的最大值,可以在枚举 i 时计算。i=1nik 前置只是里有的。所以这个题就解决了。

int getpow(int n, int k) 
{
	n = n % mod;
	pl[0] = pr[k + 3] = fac[0] = 1;
	int ans = 0, y = 0;
	for (rint i = 1; i <= k + 2; i++) pl[i] = pl[i - 1] * (n - i) % mod;
	for (rint i = k + 2; i >= 1; i--) pr[i] = pr[i + 1] * (n - i) % mod;
	for (rint i = 1; i <= k + 2; i++) fac[i] = fac[i - 1] * i % mod;
	for (rint i = 1; i <= k + 2; i++) 
	{
		y = (y + qpow(i, k)) % mod;
		int a = pl[i - 1] * pr[i + 1] % mod;
		int b = fac[i - 1] * ((k - i) & 1 ? -1 : 1) * fac[k + 2 - i] % mod;
		ans = (ans + y * a % mod * qpow(b, mod - 2) % mod) % mod;
	}
	return (ans + mod) % mod;
}

void solve(int x) 
{
	memset(c, 0, sizeof c);
	for (rint i = 2; i * i <= x; i++)
	{
		if (!(x % i)) 
		{
			p[++cnt] = i;
			while (!(x % i)) 
			{
				x /= i;
				c[cnt]++;
			}
		}		
	}
	if (x > 1) p[++cnt] = x, c[cnt] = 1;
}

void dfs_init(int x, int step) 
{
	if (x > cnt) 
	{
		int p2 = 1, flag = 1;
		for (rint i = 1; i <= cnt; i++) 
		{
			if (t[i] > 1) flag = 0;
			else if (t[i] == 1) flag = -flag;
			for (rint j = 1; j <= t[i]; j++) p2 *= p[i];
		}
		if (!flag) return ;
		res2 = (res2 + flag * qpow(p2, step) * getpow(n / p1 / p2, step) % mod) % mod;
		return ;
	}
	for (rint i = 0; i <= c[x] - k[x]; i++)
	{
		t[x] = i;
		dfs_init(x + 1, step);		
	}
}

void solve(int d, int p1, int step) 
{
	if (d == 1) step = 1;
	step++;
	int res = qpow(p1, step);
	res2 = 0;
	dfs_init(1, step);
	ans = (ans + res * res2 % mod) % mod;
}

void dfs(int x) 
{
	if (x > cnt) 
	{
		p1 = 1;
		int maxx = 0;
		bool flag = 1;
		for (rint i = 1; i <= cnt; i++)
		{
			flag &= (k[i] > 0);
			for (rint j = 1; j <= k[i]; j++) p1 *= p[i];
			if (k[i]) maxx = max(maxx, (c[i] + k[i] - 1) / k[i]);
		}
		solve(d, p1, flag ? maxx : 0);
		return ;
	}
	for (rint i = 0; i <= c[x]; i++)
	{
		k[x] = i;
		dfs(x + 1);		
	}
}

signed main() 
{
	fac[0] = 1;
	for (rint i = 1; i <= 30; i++) fac[i] = fac[i - 1] * i % mod;
	int T;
	cin >> T;
	while (T--) 
	{
		cin >> n >> d;
		cnt = ans = 0;
		solve(d);
		dfs(1);
		cout << (ans % mod + mod) % mod << endl;
	}
	return 0;
}

理性

把式子展开有一个关于 a 的二次函数:

i=1ndi2a2+2(bvi)di×a+(bvi)2

这个函数的二次项始终为正数,当 a 取对称轴时函数取到最小值:

a=i=1n(vib)dii=1ndi2(i=1ndi2)(i=1n(vib)dii=1ndi2)2+2(i=1n(bvi)di)(i=1n(vib)dii=1ndi2)+(i=1n(bvi)2)(i=1nvidi)22(i=1nvidi)(bi=1ndi)+b2(i=1ndi)2i=1ndi2+2(bi=1ndii=1nvidi)(i=1nvidibi=1ndii=1ndi2)+(i=1nb22bvi+vi2)svd=i=1nvidi,sd=i=1ndi,sd2=i=1ndi2,sv=i=1nvi,sv2=i=1nvi2nb22sv×b+sv2b2×sd22svd×sd×b+svd2sd2(nsd2sd2)b2+2(svd×sdsd2sv)b+sv2svd2sd2

代入后得到了一个只与 b 有关的二次函数, nsd2sd2 一定 0

所以,再让 b 取对称轴时函数取到最小值

b=svsvd×sdsd2nsd2sd2sv2svd2sd2(svsvd×sdsd2)2nsd2sd2sv2svd2sd2sv22svsvd×sdsd2+(svd×sdsd2)2nsd2sd2sv2svd2sd2(sv2nsd2sd22sdsd2nsd2sd2sv×svd+(sdsd2)2nsd2sd2svd2)sv2svd2sd2(sdsd2)2nsd2sd2svd2sv2nsd2sd2+2sdsd2nsd2sd2sv×svd

得到了对于一个固定的 vsd,sd2 都已知,所以只要求出 sv2,svd2,sv2,sv×svd 的期望即可。

考虑 sv2。显然有:

sv2=i=1nS2(li,ri)rili+1

直接计算即可。

设状态 fi,0/1/2/3/4 分别表示 sv,svd,sv2,sv×svd,svd2 只考虑前 i 项的期望,转移方程:

fi,0=fi1,0+li+ri2fi,1=fi1,1+dili+ri2fi,2=fi1,2+(li+ri)fi1,0+S2(li,ri)rili+1fi,3=fi1,3+li+ri2fi1,1+dili+ri2fi1,0+diS2(li,ri)rili+1fi,4=fi1,4+di(li+ri)fi1,1+di2S2(li,ri)rili+1

void add(int &x, int y) {x = (x + y) % mod;}
void mul(int &x, int y) {x = x * y % mod;}

int qpow(int a, int b)
{
	int res = 1;
	while (b)
	{
		if (b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

int inv(int x){return qpow(x, mod - 2);}
int calc(int x){return x * (x + 1) % mod * (x << 1 | 1) % mod * iv6 % mod;}
int calc(int l, int r) {return (calc(r) - calc(l - 1) + mod) % mod;}

signed main() 
{
	cin >> n;
	
	for (rint i = 1; i <= n; i++)
	{
		cin >> d[i] >> l[i] >> r[i];
		add(sd,  d[i]);
		add(sd2, d[i] * d[i] % mod);
	}
		      
	for (rint i = 1; i <= n; i++) 
	{
		int iv = inv(r[i] - l[i] + 1);
		add(ans, calc(l[i], r[i]) * iv % mod);
		add(f[i][0] = f[i - 1][0], (l[i] + r[i]) * iv2 % mod);
		add(f[i][1] = f[i - 1][1], (l[i] + r[i]) * iv2 % mod * d[i] % mod);
		add(f[i][2] = f[i - 1][2], calc(l[i], r[i]) * iv % mod);
		add(f[i][2], (l[i] + r[i]) * f[i - 1][0] % mod);
		add(f[i][3] = f[i - 1][3], calc(l[i], r[i]) * iv % mod * d[i] % mod);
		add(f[i][3], (l[i] + r[i]) * f[i - 1][1] % mod * iv2 % mod);
		add(f[i][3], (l[i] + r[i]) * f[i - 1][0] % mod * iv2 % mod * d[i] % mod);
		add(f[i][4] = f[i - 1][4], calc(l[i], r[i]) * iv % mod * d[i] % mod * d[i] % mod);
		add(f[i][4], (l[i] + r[i]) * f[i - 1][1] % mod * d[i] % mod);
	}
	
	int q = inv((n - sd * sd % mod * inv(sd2) % mod + mod) % mod);
	
	add(ans, mod - f[n][4] * inv(sd2) % mod);
	add(ans, mod - f[n][4] * qpow(sd * inv(sd2) % mod, 2) % mod * q % mod);
	add(ans, mod - f[n][2] * q % mod);
	add(ans, 2 * f[n][3] * sd % mod * inv(sd2) % mod * q % mod);
	
	cout << ans << endl;
	
	return 0;
}

本文作者:PassName

本文链接:https://www.cnblogs.com/spaceswalker/p/18158730

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   PassName  阅读(30)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起