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

题目链接:戳我

首先那个n==k很好写:对于一个题意中的序列,最少的步数是多少?
从大到小判断即可.(代码可以看subtask1)

然后我就不会写了
于是滚去看了看题解

发现对于一个局面,我们总是可以计算出它的最小关灯次数k,那么也就是说,只有这k次有用.
或者这么理解:有n个球,k个是黑的,n-k个是白的,每次可以随机选择一个把它反色,问所有球变成白的的期望次数为多少?

我们设(f[x])表示还有x个黑球.

[f[x]=frac{x}{n}f[x-1]+frac{n-x}{n}f[x+1]+1 ]

边界条件:
(f[n]=f[n-1]+1)
(f[x]=x;(xle k))

我们设(f[x]=f[x-1]+s).现在我们只知道x==n的时候,s=1.我们从n开始往下算,每一层都凭借上一层的s算出来当前层s,然后回溯的时候统计答案.

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

(f[x]=frac{x}{n}f[x-1]+frac{n-x}{n}(f[x]+s)+1)

(frac{x}{n}f[x]=frac{x}{n}f[x-1]+frac{x-n}{n}*s+1)

(f[x]=f[x-1]+frac{n-x}{x}*s+frac{n}{x})

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 100010
#define mod 100003
using namespace std;
int n,k;
int a[MAXN],fn[MAXN],inv[MAXN],ans[MAXN],ff[MAXN];
namespace subtask1
{
    int ans=0;
    inline int solve()
    {
        for(int i=n;i>=1;i--)
        {
            if(a[i]==0) continue;
            for(int j=1;j*j<=i;j++)
            {
                if(i%j==0) 
                {
                    a[j]^=1;
                    if(j*j!=i) a[i/j]^=1;
                }
            }
            ans=(ans+1)%mod;
        }
        return ans;
    }
}
namespace subtask2
{
    inline int fpow(int x,int y)
    {
        int cur_ans=1;
        while(y)
        {
            if(y&1) cur_ans=1ll*cur_ans*x%mod;
            x=1ll*x*x%mod;
            y>>=1;
        }
        return cur_ans;
    }
    inline int dfs(int x,int sum)
    {
        if(x<=k) return ans[x]=x;
        sum=(1ll*n*inv[x]%mod+1ll*sum*(n-x)%mod*inv[x]%mod)%mod;
        return ans[x]=(dfs(x-1,sum)+sum)%mod; 
    }
    inline void solve()
    {
        int cur_ans=subtask1::solve();
        ff[n]=fpow(fn[n],mod-2)%mod;
        for(int i=n-1;i>=1;i--) ff[i]=1ll*ff[i+1]*(i+1)%mod;
        for(int i=1;i<=n;i++) inv[i]=1ll*ff[i]*fn[i-1]%mod;
        for(int i=1;i<=k;i++) ans[i]=i;
        dfs(n,1);
        printf("%lld
",1ll*ans[cur_ans]*fn[n]%mod);
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    fn[0]=1;
    for(int i=1;i<=n;i++) fn[i]=1ll*fn[i-1]*i%mod;
    if(n==k) printf("%lld
",1ll*subtask1::solve()*fn[n]%mod);
    else subtask2::solve();
    return 0;
}

原文地址:https://www.cnblogs.com/fengxunling/p/11052957.html