• 【BZOJ4872】【SHOI2017】分手是祝愿 期望DP


    题目大意

      有(n)盏灯和(n)个开关,初始时有的灯是亮的,有的灯是暗的。按下第(i)个开关会使第(j)盏灯的状态被改变,其中(j|i)。每次你会随机操作一个开关,直到可以通过不多于(k)次操作使所有灯都灭掉,然后按照操作次数最小的方案操作。求期望的操作次数( imes n!~mod~100003)

      (1leq nleq 100000,0leq kleq n)

    题解

      首先不能通过操作任意个不同的开关使得灯的状态不变,因为最大那个开关对应的灯的状态一定会改变。

      所以我们每次操作亮着的灯中编号最大的那盏对应的开关,直到所有灯都灭掉。这个操作步骤一定是最优步骤。记下操作次数(num)

      设(f_i)(i)盏灯变成(i-1)盏灯期望操作次数,有:

    [egin{align} f_i&=frac{i}{n}+frac{n-i}{n}(1+f_{i+1}+f_i)\ frac{i}{n}f_i&=1+frac{n-i}{n}f_{i+1}\ f_i&=frac{n+(n-i)f_{i+1}}{i} end{align} ]

      特殊的,(f_{n+1}=0)

      最后把答案乘上(n!)

      时间复杂度:(O(nsqrt n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    ll p=100003;
    ll fp(ll a,ll b)
    {
    	ll s=1;
    	while(b)
    	{
    		if(b&1)
    			s=s*a%p;
    		a=a*a%p;
    		b>>=1;
    	}
    	return s;
    }
    int a[100010];
    ll f[100010];
    int main()
    {
    	int n,k;
    	scanf("%d%d",&n,&k);
    	int i,j;
    	for(i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	int num=0;
    	for(i=n;i>=1;i--)
    		if(a[i])
    		{
    			num++;
    			for(j=1;j*j<=i;j++)
    				if(i%j==0)
    				{
    					a[j]^=1;
    					if(j*j!=i)
    						a[i/j]^=1;
    				}
    		}
    	ll s=1;
    	f[n+1]=1;
    	for(i=n;i>=1;i--)
    		f[i]=(n+(n-i)*f[i+1]%p)%p*fp(i,p-2)%p;
    	if(num<=k)
    		s=num;
    	else
    	{
    		s=0;
    		for(i=num;i>k;i--)
    			s=(s+f[i])%p;
    		s=(s+k)%p;
    	}
    	for(i=1;i<=n;i++)
    		s=s*i%p;
    	printf("%lld
    ",s);
    	return 0;
    }
    
  • 相关阅读:
    高阶篇:4.1.2.3)产品零件级别的QFDII
    高阶篇:4.1.2.2)产品部件级别的QFDII
    高阶篇:4.1.2.1)产品总成级别的QFDII
    基础篇:3.3)规范化:3d装配图
    基础篇:3.2)规范化:3d零件建模
    基础篇:3.1)规范化:3d草绘
    [洛谷P1021][题解]邮票面值设计
    [洛谷P1290][题解]欧几里德的游戏
    [整理]两次NOI Online 提高组试题
    [洛谷P2286][题解][HNOI2004]宠物收养场
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8511375.html
Copyright © 2020-2023  润新知