• [六省联考2017]分手是祝愿


    Description:

    Zeit und Raum trennen dich und mich.

    时空将你我分开。
    B 君在玩一个游戏,这个游戏由 ​(n) 个灯和 ​(n) 个开关组成,给定这 ​(n) 个灯的初始状态,下标为从 ​(1) 到 ​(n) 的正整数。
    每个灯有两个状态亮和灭,我们用 ​(1) 来表示这个灯是亮的,用 ​(0) 表示这个灯是灭的,游戏的目标是使所有灯都灭掉。
    但是当操作第 ​(i) 个开关时,所有编号为 ​(i) 的约数(包括 ​(1) 和 ​(i))的灯的状态都会被改变,即从亮变成灭,或者是从灭变成亮。
    B 君发现这个游戏很难,于是想到了这样的一个策略,每次等概率随机操作一个开关,直到所有灯都灭掉。
    这个策略需要的操作次数很多,B 君想到这样的一个优化。如果当前局面,可以通过操作小于等于 ​(k) 个开关使所有灯都灭掉,那么他将不再随机,直接选择操作次数最小的操作方法(这个策略显然小于等于 ​(k) 步)操作这些开关。
    B 君想知道按照这个策略(也就是先随机操作,最后小于等于 ​(k) 步,使用操作次数最小的操作方法)的操作次数的期望。
    这个期望可能很大,但是 B 君发现这个期望乘以 ​(n) 的阶乘一定是整数,所以他只需要知道这个整数对 ​$$100003​$ 取模之后的结果。

    Hint:

    (n le 10^6​)

    Solution:

    首先考虑最优策略,就是从大到小能关则关

    这里大概理解一下,一来如果按一个关着的开关必定不优,因为你虽然关了它的因数,但现在又要按他的倍数,所以它的因数又会开

    同时我们发现按小的一定不能影响大的,而如果按这个小的比较优,我们从大到小也一定会先按到它

    也就是说最优策略唯一确定,要按的开关可以预处理出来(不一定一来就是开着的)

    所以我们如果按到一个不是最优策略的开关,就相当于你要多按一次按回来

    我们设(dp[i])表示按最优策略还剩i个开关要按到还剩i-1个的期望步数,则有:

    (dp[i]=frac{i}{n}*1 +frac{n-i}{n} (dp[i]+dp[i+1]+1))

    直接从(n)开始递推,因为最多按(n)

    对于答案,大于k时累加(f[i]),小于k的时候我们就直接把答案加上最优策略的步数

    至于因数,用vector预处理一下

    #include <map>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ls p<<1 
    #define rs p<<1|1
    using namespace std;
    typedef long long ll;
    const ll mxn=2e5+5,mod=100003;
    ll n,k,cnt,a[mxn],dp[mxn],inv[mxn];
    inline ll read() {
    	char c=getchar(); ll x=0,f=1;
    	while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    	while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
    	return x*f;
    }
    inline ll chkmax(ll &x,ll y) {if(x<y) x=y;}
    inline ll chkmin(ll &x,ll y) {if(x>y) x=y;}
    
    vector<ll > vec[mxn];
    
    int main()
    {
    	n=read(); k=read(); inv[1]=1; dp[n]=1;
    	for(ll i=2;i<=n;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    	for(ll i=1;i<=n;++i) a[i]=read();
    	for(ll i=1;i<=n;++i) 
    		for(ll j=i;j<=n;j+=i) 
    			vec[j].push_back(i);
    	for(ll i=n;i>=1;--i) {
    		if(!a[i]) continue ;
    		for(ll j=0;j<vec[i].size();++j) 
    			a[vec[i][j]]^=1;
    		++cnt;	
    	}		
    	for(ll i=n-1;i>k;--i) dp[i]=1ll*(n+(n-i)*dp[i+1]%mod)%mod*inv[i]%mod;
    	for(ll i=k;i>=1;--i) dp[i]=1; ll ans=0;
    	for(ll i=1;i<=cnt;++i) ans=(ans+dp[i])%mod;
    	for(ll i=1;i<=n;++i) ans=1ll*ans*i%mod;
    	printf("%d",ans);
        return 0;
    }
    
    
  • 相关阅读:
    dropload.js 上滑加载,下拉刷新
    jQuery支持图片放大缩小查看效果
    iScroll-5 API 中文版
    多行文字垂直居中
    jQuery延迟加载(懒加载)插件 – jquery.lazyload.js
    js生成中文二维码
    JS中,如何判断一个数是不是小数?如果是小数,如何判断它是几位小数??
    HTML5页面,用JS 禁止弹出手机键盘
    watch和computed的用法区别是什么?
    JS中的call()和apply()
  • 原文地址:https://www.cnblogs.com/list1/p/10527188.html
Copyright © 2020-2023  润新知