ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

来自学长的馈赠4

2022-07-25 12:35:58  阅读:119  来源: 互联网

标签:来自 int ll 学长 read while 馈赠 include getchar


打了一半就跑了,,,垫底垫底

A. 活动投票

摩尔投票,想象让投票不同的两个人同归于尽,选票过半的人的支持者肯定有活下来的

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int x = 0; char c = getchar();
    while(c < '0' || c > '9')c = getchar();
    while(c >= '0' && c <= '9')x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
int n;
int main(){
    n = read();
    int ans = 0, cnt = 0;
    for(int i = 1; i <= n; ++i){
        int x = read(); 
        if(cnt && x != ans)--cnt;
        else ++cnt, ans = x;
    }
    printf("%d\n",ans);
    return 0;
}

B. 大佬

每 \(k\) 天之间相互独立?

计算\(k\)天的期望乘上\(n - k + 1\),再除以总方案数即可

期望计算方法就是枚举最大值简单容斥

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int x = 0; char c = getchar();
    while(c < '0' || c > '9')c = getchar();
    while(c >= '0' && c <= '9')x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
const int maxn = 5005;
const int mod = 1000000007;
int n, m, k, wt[maxn];
int qpow(int x, int y){
    int ans = 1;
    for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
    return ans;
}
int main(){
    n = read(); m = read(); k = read();
    for(int i = 1; i <= m; ++i)wt[i] = read();
    int ans = 0, las = 0;
    for(int i = 1; i <= m; ++i){
        int ls = qpow(i, k);
        ans = (ans + 1ll * (ls - las + mod) % mod * wt[i] % mod) % mod;
        las = ls;
    }
    ans = 1ll * qpow(qpow(m, k), mod - 2) * ans % mod * max(n - k + 1, 0) % mod;
    printf("%d\n",ans);
    return 0;
}

C. Dp搬运工3

如果你和我一样不会摩尔投票,那么这就是全场最水的题

\(f_{i, j,k}\)表示前\(i\)个数,\(j\)个数没有配对,当前答案为\(k\)的方案数

转移考虑当前两个数是否配对,跟谁配对

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 53;
const int mod = 998244353;
ll f[maxn][maxn][maxn * maxn];
int main(){
    ll n,K; scanf("%lld%lld",&n,&K);
    f[1][1][0] = n * (n - 1);
    f[1][0][1] = n;
    for(ll i = 1; i < n; ++i){
        ll mj = min(i, n - i);
        for(ll j = 0; j <= mj; ++j){
            for(ll k = 0; k <= K; ++k)
                if(f[i][j][k]){
                    f[i][j][k] %= mod;
                    f[i + 1][j][k + i + 1] += f[i][j][k] * (n - i - j);
                    f[i + 1][j + 1][k] += f[i][j][k] * (n - i - j) * (n - i - j - 1);
                    f[i + 1][j][k + i + 1] += f[i][j][k] * 2 * (n - i - j) * j;
                    if(j)f[i + 1][j - 1][k + i + 1 + i + 1] += f[i][j][k] * j * j;
                }
        }
    }
    ll ans = 0;
    for(ll i = 0; i < K; ++i)ans += f[n][0][i]; 
    ans %= mod;
    ll sum = 1;
    for(ll i = 1; i <= n; ++i)sum = sum * i % mod;
    sum = sum * sum % mod;
    printf("%lld\n",((sum - ans) % mod + mod) % mod);
    return 0;
}

D. Beautiful

康拓展开 + 错排应用 + 简单?\(DP\) + 树状数组

第一行康拓展开

后面比较麻烦,假设你考虑到了\(i,j\)位置,那么有些数字有错排限制,有些没有,这个需要预处理出来

然后我需要知道有多少有限制的数小于当前值,多少没限制的数小于当前值,维护两个树状数组即可

没懂 ? 看代码吧。

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int x = 0; char c = getchar();
    while(c < '0' || c > '9')c = getchar();
    while(c >= '0' && c <= '9')x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return x;
}
const int maxn = 2005;
const int mod = 998244353;
int n, a[maxn][maxn], cp[maxn], bcp[maxn][maxn], fac[maxn];
bool vis1[maxn], vis2[maxn];
struct tree{
    int t[maxn];
    int lowbit(int x){return x & -x;}
    void add(int x, int d){while(x <= n){t[x] += d; x += lowbit(x);}}
    int query(int x){int ans = 0; while(x){ans += t[x]; x -= lowbit(x);}return ans;}
}T1,T2;
inline int qpow(int x, int y){
    int ans = 1;
    for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
    return ans;
}
int main(){
    n = read();
    for(int i = 1; i <= n; ++i)
      for(int j = 1; j <= n; ++j)
        a[i][j] = read();
    cp[2] = 1; for(int i = 3; i <= n; ++i)cp[i] = 1ll * (i - 1) * (cp[i - 1] + cp[i - 2]) % mod;
    fac[0] = 1; for(int i = 1; i <= n; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
    bcp[0][0] = 1;// bcp[i][j]i个数,其中j 个有错排限制
    for(int i = 1; i <= n; ++i){
        bcp[i][0] = fac[i];//钦定一个无限制的位置,考虑放一个有/无限制的数
        for(int j = 1; j < i; ++j)bcp[i][j] = (1ll * j * bcp[i - 1][j - 1]  + 1ll * bcp[i - 1][j] * (i - j)) % mod;
        bcp[i][i] = cp[i];
    }
    int ktzk = 0;
    for(int i = 1; i <= n; ++i)T1.add(i, 1);
    for(int i = 1; i <= n; ++i){
        ktzk = (ktzk + 1ll * T1.query(a[1][i] - 1) * fac[n - i] % mod) % mod;
        T1.add(a[1][i], -1);
    }
    int ans = 1ll * qpow(cp[n], n - 1) * ktzk % mod;
    for(int i = 2; i <= n; ++i){
        for(int j = 1; j <= n; ++j)T1.t[i] = 0;
        for(int j = 1; j <= n; ++j)vis1[j] = 0;
        for(int j = 1; j <= n; ++j)vis2[j] = 0;
        for(int j = 1; j <= n; ++j)T2.add(j, 1);
        //T1维护往后没有错排限制的数,T2维护有错排限制的数
        //vis1是上一行的vis,vis2是本行的vis
        int ls = 0, res = n;
        for(int j = 1; j <= n; ++j){
            if(!vis2[a[i - 1][j]])--res, T2.add(a[i - 1][j], -1);//本行没有出现过a[i - 1][j],那么它不再是有限制的数,但是它不能出现在当前位置。所以加入操作在统计答案之后
            ls = (ls + 1ll * T1.query(a[i][j] - 1) * bcp[n - j][res] % mod) % mod;//放无限制,比当前小
            if(res) ls = (ls + 1ll * T2.query(a[i][j] - 1) * bcp[n - j][res - 1] % mod) % mod;//有限制,比当前小
            if(!vis2[a[i - 1][j]])T1.add(a[i - 1][j], 1);//加入操作
            if(vis1[a[i][j]])T1.add(a[i][j], -1);//如果上一行之前访问过a[i][j]那么此时它没有限制,从T1中删
            else T2.add(a[i][j], -1);//否则它在T2中删
            //这里是在消除a[i][j],因为之后不能用它了
            vis1[a[i - 1][j]] = vis2[a[i][j]] = 1;//打vis
            if(!vis1[a[i][j]])--res;//上一行没有出现过当前数,它没有限制了 res = T2.query(n)
        }
        ans = (ans + 1ll * ls * qpow(cp[n],n - i) % mod) % mod;
    }
    printf("%d\n",ans % mod);
    return 0;
}

标签:来自,int,ll,学长,read,while,馈赠,include,getchar
来源: https://www.cnblogs.com/Chencgy/p/16516986.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有