zoukankan      html  css  js  c++  java
  • [SHOI 2017] 分手是祝愿

    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=4872

    [算法]

             首先发现 , 对于一个开关 , 按下2次和没按是等价的 , 因此每个开关最多按一次

             考虑k = n的情况 , 只需简单倒序贪心即可

             考虑随机的情况 , 由观察可知一个开关不能由多个开关组合得到

             用fi表示i次将所有开关变关到(i - 1)次将所有开关变关的期望步数

             有转移方程fi = i / n + (1 - i / n) * (1 + fi + 1 + fi)

             将该转移方程看作一个一元一次方程 , 即可解出fi

             不再赘述 , 详见代码

             时间复杂度 : O(N)

    [代码]

             

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int P = 100003;
    const int N = 100010;
    
    int n , k , cnt;
    int a[N] , inv[N] , dp[N];
    vector< int > D[N];
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    
    int main()
    {
        
        read(n); read(k);
        for (int i = 1; i <= n; ++i) read(a[i]);
        inv[1] = 1;
        for (int i = 2; i <= n; ++i) inv[i] = 1ll * (P - P / i) * inv[P % i] % P;
        for (int i = 1; i <= n; ++i)
        {
            for (int j = i; j <= n; j += i)
            {
                D[j].push_back(i);
            }    
        }
        for (int i = n; i >= 1; --i)
        {
            if (a[i])
            {
                for (unsigned j = 0; j < D[i].size(); ++j)
                    a[D[i][j]] ^= true;
                ++cnt;
            }
        }
        int ans = 0;
        if (cnt <= k)
            ans = cnt;
        else
        {
            dp[n] = 1;
            for (int i = n - 1; i >= 1; --i) dp[i] = (1ll * dp[i + 1] * (n - i) % P * inv[i] % P + 1ll * n * inv[i] % P) % P;
            for (int i = cnt; i > k; --i) ans = (ans + dp[i]) % P;
            ans = (ans + k) % P;
        }
        for (int i = 1; i <= n; ++i) ans = 1ll * ans * i % P;
        printf("%d
    " , ans);
        
        return 0;
        
    }

          

  • 相关阅读:
    ObjectArx的一次常用方法
    GDI+ 简介(1)
    VC++获取可执行文件当前目录
    SQL Server 常用的时间处理函数
    利于Wininet创建一个FTP客户端的步骤
    Win32 文件操作的几个API
    ObjectARX中三维多段线转二维多段线的方法
    fas文件格式解析
    [转载]swf文件格式解析(一)
    [转载]swf文件格式解析(二)
  • 原文地址:https://www.cnblogs.com/evenbao/p/10623825.html
Copyright © 2011-2022 走看看