P3750 [六省联考2017]分手是祝愿(期望概率,返祖模型)

题意:给n个灯,初始化下给出每个灯的状态,给n个开关,操作开关i会使得编号是i的约数的灯的状态翻转一次,现在有一个种算法,如果当前状态下可以操作k次及以下就能使所有灯熄灭,直接操作这个次数,游戏结束,否则随机按一次开关。

分析与总结:首先根据初始化的状态,可以知道最少操作几次使得全部灯都灭,那就是从高位开始操作(这个很显然)。
然后分析下,假设现在有num个灯是开的,那么显然可以画出下面这个返祖模型。
在这里插入图片描述
根据这个状态转移图,可以列出方程 f [ i ] = n / i ∗ 1 + ( n − i ) / n ∗ ( 1 + f [ i + 1 ] + f [ i ] ) f[i]=n/i*1+(n-i)/n*(1+f[i+1]+f[i]) f[i]=n/i1+(ni)/n(1+f[i+1]+f[i])
化简后可以得到 f [ i ] = ( n + ( n − i ) ∗ f [ i + 1 ] ) / i f[i]=(n+(n-i)*f[i+1])/i f[i]=(n+(ni)f[i+1])/i
然后判断到k次之后直接退出就好,注意前期是随机化操作,所以从n开始dp。

int a[N];
ll f[N];
ll fa[N];
int main()
{
#ifndef ONLINE_JUDGE 
	freopen("in.txt", "r", stdin);
#endif

	int n, k;
	fa[0] = 1;
	f(i, 1, N-1	)fa[i] = fa[i - 1] * i%mod;
	while (cin >> n >> k)
	{
		f(i, 1, n)a[i] = in();
		ll num = 0;
		ff(i, n, 1)//n*sqrt(n)
		{
			if (a[i])
			{
				num++;
				for (int j = 1;j*j <= i;j++)
				{
					if (i%j == 0)
					{
						a[j] ^= 1;
						if (j*j!=i)a[i / j] ^= 1;
					}
				}
			}
		}
		f[n + 1] = 0;
		ll tmp = 0;
		if (num <= k)   tmp = num;
		else {
			for (int i = n;i > k;i--)
			{
				ll tmp2= (ll)(n - i)*f[i + 1] % mod;
				tmp2 = (tmp2 + (ll)n) % mod;
				tmp2 = tmp2 * quickmod(i, mod - 2,mod) % mod;
				f[i] = tmp2;
				if(i<=num)
				tmp = (tmp + f[i]) % mod;
			}
			tmp = (tmp + k) % mod;
		}
		tmp = tmp* fa[n] % mod;
		printf("%lld\n",tmp);
	}
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值