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


BZOJ
Luogu

sol

首先发现肯定有解,又因为每个位置至多操作一次,所以最优解一定是在\([0,n]\)之间
有一种可以在\(O(\sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor)\)复杂度求最优解的方法。
只要枚举这个数的倍数判断被操作了几次就行了。
如果最优步数小于等于k直接输出最优步数\(*n!\)
否则,我们设\(f_i\)表示当前最优步数是\(i\)时的期望完成步数
考虑到这时所有位置已经没有区别了(只有需要操作的和不需要操作的两种,没有顺序区别),所以这个状态是成立的
那么
\[f_i=\frac{i}{n}f_{i-1}+\frac{n-i}{n}f_{i+1}+1\]
方程显然有解,然而直接高斯消元\(O(n^3)\)
考虑把\(f_i\)差分,记为\(g_i\),那么上式就变成了
\[\sum_{x=1}^{i}g_x=\frac{i}{n}\sum_{x=1}^{i-1}g_x+\frac{n-i}{n}\sum_{x=1}^{i+1}g_x+1\]
化简
\[g_i=\frac{n-i}{n}(g_i+g_{i+1})+1\]
so
\[g_i=\frac{(n-i)g_{i+1}+n}{i}\]
逆元线性推得

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int mod = 100003;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
int n,jc=1,k,a[mod],opt[mod],best,inv[mod],f[mod],ans;
int main()
{
    n=gi();k=gi();
    for (int i=1;i<=n;++i) a[i]=gi(),jc=1ll*jc*i%mod;
    for (int i=n;i;--i)
    {
        int p=a[i];
        for (int j=i+i;j<=n;j+=i) p^=opt[j];
        if (p) opt[i]=1,++best;
    }
    if (best<=k) return printf("%lld\n",1ll*best*jc%mod),0;
    inv[1]=f[n]=1;
    for (int i=2;i<=n;++i) inv[i]=(mod-1ll*(mod/i)*inv[mod%i]%mod)%mod;
    for (int i=n-1;i>k;--i) f[i]=(1ll*(n-i)*f[i+1]%mod+n)%mod*inv[i]%mod;
    for (int i=1;i<=best;i++) ans+=i<=k?1:f[i];
    return printf("%lld\n",1ll*ans*jc%mod),0;
}
优质内容筛选与推荐>>
1、Linux下查看、关闭及开启防火墙命令
2、云HR市场财务运营指数分析看2018年风云变化
3、FFmpeg总结(九)用ffmpeg进行切片生成m3u8索引文件
4、reactor-rabbitmq小试牛刀
5、如何在Kerberos环境使用Flume采集Kafka数据并写入HDFS


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号