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


    BZOJ
    Luogu

    sol

    首先发现肯定有解,又因为每个位置至多操作一次,所以最优解一定是在([0,n])之间
    有一种可以在(O(sum_{i=1}^{n}lfloorfrac{n}{i} floor))复杂度求最优解的方法。
    只要枚举这个数的倍数判断被操作了几次就行了。
    如果最优步数小于等于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
    ",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
    ",1ll*ans*jc%mod),0;
    }
    
  • 相关阅读:
    Effective C++ 学习笔记(12)
    Effective C++ 学习笔记(6)
    Effective C++ 学习笔记(13)
    Effective C++ 学习笔记(11)
    Effective C++ 学习笔记(10)
    (转)C++函数后加const的意义
    Effective C++ 学习笔记(14)
    Effective C++ 学习笔记(7)
    Effective C++ 学习笔记(9)
    Effective C++ 学习笔记(8)
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8424095.html
Copyright © 2020-2023  润新知