2021SCUACM集训队冬季选拔2大部分题解

Posted hans774882968

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021SCUACM集训队冬季选拔2大部分题解相关的知识,希望对你有一定的参考价值。

传送门

本来在预习课程期末的,结果还是没能忍住来写了一套题

A

签到。数有多少个个位为9的。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 3e5 + 5;

int n;

void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r) 
    cout << f << " ";
    dbg(r...);

template<typename Type>inline void read(Type &xx)
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;

void read()
template<typename T,typename ...R>void read(T &x,R &...r)
    read(x);
    read(r...);


int main(int argc, char** argv) 
    int T;read(T);
    while(T--)
        read(n);
        printf("%d\\n",(n+1)/10);
    
    return 0;

B

看到m <= 1000就猜到大约是m^2的算法,所以显然要先取模+开桶计数。把模m的和看成重量,于是转化为多重背包求是否存在方案的问题。

但麻烦的是,不能直接用dp[m][0],因为它受到dp[0][0] = true的影响,必然为true;并且也无法直接算方案数。那么我们就在dp转移的过程中监听即可。

不难的一个背包居然tag是1900

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 1e3 + 5;

int n,m,c[N];bool dp[N*15][N];

void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r) 
    cout << f << " ";
    dbg(r...);

template<typename Type>inline void read(Type &xx)
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;

void read()
template<typename T,typename ...R>void read(T &x,R &...r)
    read(x);
    read(r...);


void pack(int &tot,bool &ans,int v,int w)
    if(!v) return;
    ++tot;
    dwn(j,m-1,0)
        dp[tot][j] = dp[tot-1][j] || dp[tot-1][(j-w+m)%m];
        if(!j) ans |= dp[tot-1][(j-w+m)%m];
    


int main(int argc, char** argv) 
    read(n,m);
    rep(i,1,n)
        int x;read(x);c[x%m+1]++;
    
    dp[0][0] = true;
    int tot = 0;bool ans = false;
    rep(i,1,m)
        int u = c[i];
        for(int j = 0;(1 << j) < u;++j)
            pack(tot,ans,1<<j,(1<<j)*(i-1)%m);
            u -= (1 << j);
        
        pack(tot,ans,u,u*(i-1)%m);
    
    puts(ans ? "YES" : "NO");
    return 0;

C

签到。简单分类讨论。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 3e5 + 5;

int n;

void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r) 
    cout << f << " ";
    dbg(r...);

template<typename Type>inline void read(Type &xx)
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;

void read()
template<typename T,typename ...R>void read(T &x,R &...r)
    read(x);
    read(r...);


int main(int argc, char** argv) 
    int T;read(T);
    while(T--)
        read(n);int s = 0;
        rep(i,1,n)
            int x;read(x);s += x;
        
        if(s >= n) printf("%d\\n",s-n);
        else puts("1");
    
    return 0;

D

待填坑~

E

一看就很组合数学,而且没法dp。突破口就是令一些房间为空。于是非空的房间相当于经典的方程求解的个数问题,如果没听说过,可以参考我的这篇介绍

枚举空房间个数i = 0~min(n-1,k),则C(n,i)选出空房间,C(n-i+i-1,i)表示n-i个变量,和为i的方案数,乘起来就是贡献。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 3e5 + 5,mod = 1e9 + 7;

int n,k;LL fac[N],ifac[N];

void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r) 
    cout << f << " ";
    dbg(r...);

template<typename Type>inline void read(Type &xx)
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;

void read()
template<typename T,typename ...R>void read(T &x,R &...r)
    read(x);
    read(r...);


LL q_pow(LL a,LL b,LL mod)
    LL ret = 1;
    for(;b;b >>= 1)
        if(b & 1) ret = ret * a % mod;
        a = a * a % mod;
    
    return ret;


void init(int n)
    fac[0] = 1;rep(i,1,n) fac[i] = fac[i-1] * i % mod;
    ifac[n] = q_pow(fac[n],mod-2,mod);
    dwn(i,n-1,0) ifac[i] = (i+1) * ifac[i+1] % mod;


LL C(int x,int y)
    if(x < y) return 0;
    return fac[x] * ifac[y] % mod * ifac[x-y] % mod;


int main(int argc, char** argv) 
    read(n,k);
    init(n);
    int ans = 0;
    rep(i,0,min(n-1,k))
        ans = (ans + C(n,i) * C(n-1,i) % mod) % mod;
    printf("%d\\n",ans);
    return 0;

F

贪心依据是排序不等式。贪心过程需要一个数据结构,维护当前可选但未选的下标,支持插入、删除和求最小权值。这个数据结构就是优先队列。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i 以上是关于2021SCUACM集训队冬季选拔2大部分题解的主要内容,如果未能解决你的问题,请参考以下文章

SCUACM22暑假集训前劝退赛部分题解

四川大学2021SCUACM新生赛决赛大部分题解(差分dp线段树……)

2019CSUST集训队选拔赛题解

2017冬季24集训模拟-3.耀西岛

2017冬季24集训模拟-1.寻找幽灵

2017冬季24集训模拟-4.排座椅