[ABC201]Secret Number

壹、题目描述 ¶

传送门 to Atcoder.

中文描述:

一个 \(\rm PIN\)四位数字组成,可以包含重复的数字;

给你一个长度为 \(10\) 的字符串,下标从 \(0\) 开始。对于 \(s_i\),它的含义如下:

  • \(s_i=\tt{o}\),则要求构造的 \(\rm PIN\) 必须有数字 \(i\)
  • \(s_i=\tt{x}\),则要求构造的 \(\rm PIN\) 必须没有数字 \(i\)
  • \(s_i=\tt{?}\),则要求构造的 \(\rm PIN\) 不一定要包含数字 \(i\)

对于给定的字符串,有多少种不同的 \(\rm PIN\) 码?

数据范围:\(|S|=10,s_i\in\{\tt{o,x,?}\}\).

贰、题解 ¶

只有 \(4\) 位!只有 \(10\) 个字符!那么我们可以直接上 \(\mathcal O(10^4)\) 或者 \(\mathcal O(10^4\times 10)\) 的算法了。


加强版试题:

一个 \(\rm NIP\)\(n\) 个颜色组成,可以包含重复的颜色;

给你一个长度为 \(m\) 的字符串,下标从 \(0\) 开始。对于 \(s_i\),它的含义如下:

  • \(s_i=\tt{o}\),则要求构造的 \(\rm NIP\) 必须有颜色 \(i\)
  • \(s_i=\tt{x}\),则要求构造的 \(\rm NIP\) 必须没有颜色 \(i\)
  • \(s_i=\tt{?}\),则要求构造的 \(\rm NIP\) 不一定要包含颜色 \(i\)

对于给定的字符串,有多少种不同的 \(\rm NIP\) 码?答案对 \(998244353\) 取模。

数据范围:\(m\le 10^6,n\le 10^9\).

我们可以使用容斥!具体容斥有多少个没有填的必填颜色数量,记 \(k\) 为必填颜色种数,\(p\)可以填的颜色(即必填、不一定都算在里面),那么我们就有容斥的式子:

\[\sum_{i=0}^k(-1)^i{k\choose i}\times (p-i)^n \]

时间复杂度 \(\mathcal O(m\log n)\).

叁、参考代码 ¶

时间复杂度 \(\mathcal O(10^4)\).

char s[maxn+5];
 
int vis[maxn+5], cnt;
 
int ans=0;
 
void dfs(int u, int now){
    if(u==5){
        if(now==cnt) ++ans;
        return;
    }
    rep(i, 0, 9) if(s[i]!='x'){
        if(!vis[i] && s[i]=='o') ++now;
        ++vis[i];
        dfs(u+1, now);
        if((--vis[i])==0){
            if(s[i]=='o') --now;
        }
    }
}
 
signed main(){
    scanf("%s", s);
    rep(i, 0, 9) if(s[i]=='o')
        ++cnt;
    if(cnt>4) return printf("0\n"), 0;
    dfs(1, 0);
    printf("%d\n", ans);
    return 0;
}

时间复杂度 \(\mathcal O(m\log n)\)(请忽略 \(\tt mypow\) 的复杂度,把他当成 \(\log\) 的快速幂吧)

#define int long long

const int maxn=10;
const int maxc=10;

char s[maxn+5];
int C[maxc+5][maxc+5], fac[maxc+5];
int cnto, cnt;

inline void init(){
    fac[0]=1;
    rep(i, 1, maxc) fac[i]=fac[i-1]*i;
    rep(i, 0, maxc){
        C[i][0]=C[i][i]=1;
        rep(j, 1, i-1)
            C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
}

inline int mypow(int a, int n){
    int ret=1;
    rep(i, 1, n) ret*=a;
    return ret;
}

signed main(){
    init();
    scanf("%s", s);
    rep(i, 0, 9){
        cnto+=(s[i]=='o');
        cnt+=(s[i]=='o' || s[i]=='?');
    }
    int ans=0;
    rep(i, 0, cnto){
        ans=ans+C[cnto][i]*((i&1)? -1: 1)*mypow(cnt-i, 4);
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2021-05-16 11:31  Arextre  阅读(215)  评论(0编辑  收藏  举报