[CF1228] 简要题解

Posted qrsikno

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1228] 简要题解相关的知识,希望对你有一定的参考价值。

A

题意

\(l \le x \le r\)的所有数位不同的数\(x\), 任意输出一个.

\(1 \leq l \leq r \leq 10 ^5\)

Solution

按照题意模拟即可.

#include <bits/stdc++.h>
 
using namespace std;
#define rep(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
template <typename T> bool chkmax(T &a, const T &b)  return a < b ? a = b, true : false; 
template <typename T> bool chkmin(T &a, const T &b)  return a > b ? a = b, true : false; 
template <typename T> T getSign(const T&a)  return (a > T(0)) - (a < T(0)); 
typedef long long LL;
typedef long double LD;
const double pi = acos(-1);
void procStatus() 
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;

int read() 
    int x = 0, flag = 1;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;

void write(LL x) 
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar(x % 10 + '0');
 

int l, r;
void Init() 
    l = read(), r = read();


bool check(int val) 
    static int tmp[20], cnt; cnt = 0;
    while (val) 
        tmp[++cnt] = val % 10, val /= 10;
    sort(tmp + 1, tmp + cnt + 1);
    return cnt == unique(tmp + 1, tmp + cnt + 1) - (tmp + 1);


void Solve() 
    rep (i, l, r) 
        if (check(i)) 
            printf("%d\n", i);
            exit(0);
        
    puts("-1");


int main() 
//  freopen("bosky.in", "r", stdin);
//  freopen("bosky.out", "w", stdout);

    Init();
    Solve();

#ifdef Qrsikno
    debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;

B

题意

有一个被黑白染色的\(h \times w\)的网格, 定义\(r_i\)表示从上到下第i行\([1, r_i] \cap N^+\)全部是黑色, 并且第i行\(r_i + 1\)为白色(如果该位置在网格内), 定义\(c_i\)表示从左到右第i列\([1, c_i] \cap N^+\)全部是黑色, 并且第i列\(c_i + 1\)为白色(如果该位置在网格内), 其他位置的情况不清楚.

给定\(h, w, r_i, c_i\)求满足条件的网格方案数, 答案对\(10^9 + 7\)取模的答案.

Solution

在矩阵上打标记, 没有被打标记的地方随便填, 这部分对答案的贡献是\(2 ^cnt\)

注意可能给出的矩阵本身不合法.

#include <bits/stdc++.h>
 
using namespace std;
#define rep(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
template <typename T> bool chkmax(T &a, const T &b)  return a < b ? a = b, true : false; 
template <typename T> bool chkmin(T &a, const T &b)  return a > b ? a = b, true : false; 
template <typename T> T getSign(const T&a)  return (a > T(0)) - (a < T(0)); 
typedef long long LL;
typedef long double LD;
const double pi = acos(-1);
void procStatus() 
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;

int read() 
    int x = 0, flag = 1;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;

void write(LL x) 
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar(x % 10 + '0');
 

const int Maxn = 3009, Mod = 1e9 + 7;
int h, w, r[Maxn], c[Maxn];

void Init() 
    h = read(), w = read();
    rep (i, 1, h) r[i] = read();
    rep (i, 1, w) c[i] = read();


int vis[Maxn][Maxn], col[Maxn][Maxn];

bool judge() 
    int flag = 1;
    rep (i, 1, h) 
        if (r[i] == 0) 
            flag &= (!col[i][1]);
        else 
        if (r[i] != w) flag &= (col[i][r[i]] && !col[i][r[i] + 1]);
    
    if (!flag) return 0;
    rep (i, 1, w) 
        if (c[i] == 0) 
            flag &= (!col[1][i]);
        else if (c[i] != h) flag &= (col[c[i]][i] && !col[c[i] + 1][i]);
    
    return flag;    


void Solve() 
    rep (i, 1, h) 
        rep (j, 1, r[i] + 1) vis[i][j] = 1;
    rep (i, 1, w)
        rep (j, 1, c[i] + 1) vis[j][i] = 1;
    rep (i, 1, h) 
        rep (j, 1, r[i]) col[i][j] = 1;
    rep (i, 1, w)
        rep (j, 1, c[i]) col[j][i] = 1;

    if (!judge()) 
        cout << 0 << endl;
        return ;
    
    int cnt = h * w;
    rep (i, 1, h)
        rep (j, 1, w) cnt -= vis[i][j];
    int ans = 1;
    rep (i, 1, cnt) ans = (ans << 1) % Mod;
    cout << ans << endl;


int main() 
//  freopen("bosky.in", "r", stdin);
//  freopen("bosky.out", "w", stdout);

    Init();
    Solve();

#ifdef Qrsikno
    debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;

C

题意

定义\(prime(x)\)表示x因子中的质数形成的集合(\(prime(140)=\2,7,5\\)), \(g(x, p)\)表示整除\(x\)的最大的质数\(p\)的次幂(\(g(45, 3) = 3^2, g(100, 3) = 3^0\)), $f(x, y) = \prod_p \in prime(x) g(y, p) $.

现在给定\(x, n\), 计算\(\prod_i = 1^n g(x, i) \pmod 1e9 + 7\)

\(x \leq 10^9, n \leq 10^18\)

Solution

考虑每个x的质因子的贡献, 对于一个质因子\(p\), \(p\)的倍数会因为\(p\)被算一次, \(p^2\)的倍数会因为\(p^2\)被算一次.

\(x\)质因数分解, 暴力枚举每个质数的幂计算, 注意可能最后一次计算质数的幂会爆\(LL\)

#include <bits/stdc++.h>
 
using namespace std;
#define rep(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
template <typename T> bool chkmax(T &a, const T &b)  return a < b ? a = b, true : false; 
template <typename T> bool chkmin(T &a, const T &b)  return a > b ? a = b, true : false; 
template <typename T> T getSign(const T&a)  return (a > T(0)) - (a < T(0)); 
typedef long long LL;
typedef long double LD;
const double pi = acos(-1);
void procStatus() 
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;

LL read() 
    LL x = 0, flag = 1;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;

void write(LL x) 
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar(x % 10 + '0');
 

const int Mod = 1e9 + 7;

LL x, n;
void Init() 
    x = read(), n = read();


vector <LL> divs;

int fpm(int base, LL tims) 
    tims %= (Mod - 1);
    int r = 1;
    while (tims) 
        if (tims & 1) r = 1ll * base * r % Mod;
        base = 1ll * base * base % Mod;
        tims >>= 1;
    
    return r;


void Solve() 
    rep (i, 2, sqrt(x)) 
        if (x % i == 0) 
            divs.push_back(i);
            while (x % i == 0) x /= i;
        
    if (x != 1) divs.push_back(x);
    LL ans = 1;
    rep (i, 0, divs.size() - 1) 
        LL val = divs[i], cnt = 0;
        while (val <= n) 
            cnt += n / val;
            if (n / divs[i] < val) break;
            val = val * divs[i];
        
        ans = 1ll * ans * fpm(divs[i], cnt) % Mod;
    
    cout << ans << endl;


int main() 
//  freopen("bosky.in", "r", stdin);
//  freopen("bosky.out", "w", stdout);

    Init();
    Solve();

#ifdef Qrsikno
    debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;

D

题意

给你一个\(n\)个点\(m\)条边的图, 要求进行三分图染色, 要求三种颜色每种颜色的点都向另外两种颜色的所有点连边, 颜色内部没有边, 不能没有点不被染色, 必须要有三种颜色出现.

给出一种合法方案或判定无解.

\(n \leq 10^5\), \(m \leq 3e5\)

Solution

随便选取一个点, 与之相邻的必定是2/3色, 与之不相邻的必定是1色, 调整与之相邻的点的状态, 如果无法调整判定无解, 还要判定一些别的部分, 详见代码.

#include <bits/stdc++.h>
 
using namespace std;
#define rep(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
template <typename T> bool chkmax(T &a, const T &b)  return a < b ? a = b, true : false; 
template <typename T> bool chkmin(T &a, const T &b)  return a > b ? a = b, true : false; 
template <typename T> T getSign(const T&a)  return (a > T(0)) - (a < T(0)); 
typedef long long LL;
typedef long double LD;
const double pi = acos(-1);
void procStatus() 
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;

LL read() 
    LL x = 0, flag = 1;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;

void write(LL x) 
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar(x % 10 + '0');
 

const int Mod = 1e9 + 7;

LL x, n;
void Init() 
    x = read(), n = read();


vector <LL> divs;

int fpm(int base, LL tims) 
    tims %= (Mod - 1);
    int r = 1;
    while (tims) 
        if (tims & 1) r = 1ll * base * r % Mod;
        base = 1ll * base * base % Mod;
        tims >>= 1;
    
    return r;


void Solve() 
    rep (i, 2, sqrt(x)) 
        if (x % i == 0) 
            divs.push_back(i);
            while (x % i == 0) x /= i;
        
    if (x != 1) divs.push_back(x);
    LL ans = 1;
    rep (i, 0, divs.size() - 1) 
        LL val = divs[i], cnt = 0;
        while (val <= n) 
            cnt += n / val;
            if (n / divs[i] < val) break;
            val = val * divs[i];
        
        ans = 1ll * ans * fpm(divs[i], cnt) % Mod;
    
    cout << ans << endl;


int main() 
//  freopen("bosky.in", "r", stdin);
//  freopen("bosky.out", "w", stdout);

    Init();
    Solve();

#ifdef Qrsikno
    debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;

E

题意

给定\(n, k\), 要求给\(n \times n\)的网格填数$ \in [1, k] \cap N^+$,要求每行每列至少出现一个1.

\(n \leq 250, k \leq 10^9\)

Bonus: \(n \leq 10^5\)

Solution

正解给的做法是Dp.

\(Dp[i][j]\)表示我填完了前\(i\)行, 现在还有j个列没有给\(1\).

转移分两种: 1. 在j个里面选一些填1; 2. 在n - j里面选一些填入1.

然后就是:

  1. \[dp[i + 1][l] \leftarrow dp[i][j] j \choose l (k - 1)^l k^n - j\];

  2. \[dp[i + 1][j] \leftarrow dp[i][j] n - j\choose x (k - 1)^n - x [x \geq 1]\]

预处理组合数和幂就可以做到\(O(n^3)\)

还有一种容斥做法:

设性质\(P_j\)表示第\(j\)个位置满足条件(j <= n, 为行, j > n为列):
\[ \beginaligned Ans &= \sum_i = 0^n \sum_j = 0^n (-1)^i + jn \choose in \choose jk^n^2 - (i + j)n + ij(k - 1)^(i + j)n-ij \&= \sum_i = 0^n \sum_j = 0^n (-1)^i(-1)^jn \choose in \choose jk^(n - i)(n - j)(k - 1)^j(n - i) + ni\&= \sum_i = 0^n(-1)^in \choose i(k - 1)^ni \sum_j = 0^n n \choose j(k^n -i)^n - j(-(k - 1)^n - i)^j \&= \sum_i = 0^n(-1)^in \choose i(k - 1)^ni (k^n-i -(k - 1)^n - i)^n \endaligned \]
去掉快速幂的复杂度就是O(n)的.

#include <bits/stdc++.h>
 
using namespace std;
#define rep(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
template <typename T> bool chkmax(T &a, const T &b)  return a < b ? a = b, true : false; 
template <typename T> bool chkmin(T &a, const T &b)  return a > b ? a = b, true : false; 
template <typename T> T getSign(const T&a)  return (a > T(0)) - (a < T(0)); 
typedef long long LL;
typedef long double LD;
const double pi = acos(-1);
void procStatus() 
    ifstream t("/proc/self/status");
    cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;

LL read() 
    LL x = 0, flag = 1;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;

void write(LL x) 
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar(x % 10 + '0');
 

const int Maxn = 300, Mod = 1e9 + 7;
int n, k, power1[Maxn], power2[Maxn];
int fac[Maxn], _inv[Maxn], invFac[Maxn];

void Init() 
    n = read(), k = read();
    power1[0] = power2[0] = 1;
    rep (i, 1, n) 
        power1[i] = power1[i - 1] * (k - 1ll) % Mod;
        power2[i] = power2[i - 1] * 1ll * k % Mod;
    
    fac[0] = 1;
    rep (i, 1, n) fac[i] = fac[i - 1] * 1ll * i % Mod;
    _inv[1] = 1;
    rep (i, 2, n) _inv[i] = 1ll * _inv[Mod % i] * (Mod - Mod / i) % Mod;
    invFac[0] = 1;
    rep (i, 1, n) 
        invFac[i] = invFac[i - 1] * 1ll * _inv[i] % Mod;


inline int C(int _n, int _m) 
    if (_n < _m) return 0;
    return 1ll * fac[_n] * invFac[_m] % Mod * invFac[_n - _m] % Mod;


void Solve() 
    static int dp[Maxn][Maxn];

    dp[0][n] = 1;
    rep (i, 0, n)
        rep (j, 0, n) 
            if (dp[i][j] == 0) continue;
            rep (l, 0, j - 1) 
                dp[i + 1][l] += dp[i][j] * 1ll * C(j, l) % Mod * power1[l] % Mod * power2[n - j] % Mod;
                if (dp[i + 1][l] >= Mod) dp[i + 1][l] -= Mod;
            
            if (j) 
                rep (l, 1, n - j) 
                    dp[i + 1][j] += dp[i][j] * 1ll * C(n - j, l) % Mod * power1[n - l] % Mod;
                    if (dp[i + 1][j] >= Mod) dp[i + 1][j] -= Mod;
                
            if (j == 0) 
                rep (l, 1, n) 
                    dp[i + 1][0] += dp[i][0] * 1ll * C(n, l) % Mod * power1[n - l] % Mod;
                    if (dp[i + 1][0] >= Mod) dp[i + 1][0] -= Mod;
                
        
    cout << dp[n][0] << endl;


int main() 
    freopen("bosky.in", "r", stdin);
    freopen("bosky.out", "w", stdout);

    Init();
    Solve();

#ifdef Qrsikno
    debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;

F

??????????????????

以上是关于[CF1228] 简要题解的主要内容,如果未能解决你的问题,请参考以下文章

CF1348 简要题解

CF1354&CF1355 简要题解

CF1329 简要题解

CF1149 简要题解

CF1083(Round #526 Div. 1) 简要题解

CF1228D Complete Tripartite