zoukankan      html  css  js  c++  java
  • [六省联考2017] 分手是祝愿

    一、题目

    点此看题

    二、解法

    (50) 分的做法可以一眼看出来,就是我们从后往前关灯,可以证明这样步数一定是最小的,但其实可以得 (75)

    其实上面的方法不止是最小的,而且是唯一的。意思是如果只看成单个灯的开关的话,一定是某个灯被按奇数次,某个灯被按偶数次,这是唯一确定的。知道了这个就可以抛弃掉那个很操蛋的修改约数了。

    剩下的就是期望 (dp) 乱搞了,传统方法是定义 (f[i]) 还剩 (i) 个灯要关的期望步数,本题不能直接高斯消元,但是可以让 (f[i]=f[i-1]+b[i]) 来推 (b[i])(这种方法就不展开讲了)

    还有更好的方法,把开关灯的过程定义在状态里面(其实也有先例),设 (f[i]) 表示从 (i) 个灯关到 (i-1) 个灯的期望步数,那么转移就很好写了:

    [f[i]=1+frac{n-i}{n} imes (f[i]+f[i+1]) ]

    也就是有 (frac{n-i}{n}) 的概率按错就需要倒回去重新按,我们把这个柿子移下项:

    [f[i]=frac{n+(n-i) imes f[i+1]}{i} ]

    那么就可以直接 (O(n)) 递推了,算答案的时候求出最小按的次数 (cnt),如果这个次数比 (k) 小那么直接就是答案,否则从 (f[cnt]+f[cnt-1]...+f[k+1]) 求出到使用最小方案的期望步数,乘上 (n) 的阶乘即可。

    #include <cstdio>
    #define int long long
    const int M = 100005;
    const int MOD = 100003;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,k,cnt,ans,a[M],f[M];
    int qkpow(int a,int b)
    {
    	int r=1;
    	while(b>0)
    	{
    		if(b&1) r=r*a%MOD;
    		a=a*a%MOD;
    		b>>=1;
    	}
    	return r;
    }
    signed main()
    {
    	n=read();k=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	for(int i=n;i>=1;i--)
    	{
    		f[i]=(n+(n-i)*f[i+1]%MOD)*qkpow(i,MOD-2)%MOD;
    		if(a[i])
    		{
    			cnt++;
    			for(int j=1;j*j<=i;j++)
    				if(i%j==0)
    				{
    					a[j]^=1;
    					if(j*j!=i) a[i/j]^=1;
    				}
    		}
    	}
    	if(cnt<=k) ans=cnt;
    	else
    	{
    		for(int i=cnt;i>k;i--) ans=(ans+f[i])%MOD;
    		ans=(ans+k)%MOD;
    	}
    	for(int i=1;i<=n;i++) ans=ans*i%MOD;
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    软件工程(2018)第一次作业
    SQA计划
    再冲刺
    第三次冲刺
    第二次冲刺
    小组第一次冲刺
    团队合作初体验
    关于git的认识与想法
    我的第一篇博客
    SQA计划和系统测试规程
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14598403.html
Copyright © 2011-2022 走看看