[Codeforces Gym 101651/100725B] Banal Tickets

4 篇文章 0 订阅
1 篇文章 0 订阅

Codeforces Gym 100725
题解:
先分两种情况, 积为 0 0 与积非0, 积为 0 0 的情况容斥求解即可。
考虑积非0的情况
dp1(i,c2,c3,c5,c7) d p 1 ( i , c 2 , c 3 , c 5 , c 7 ) 表示考虑左边n个数中到第 i i 个数为止积为2c23c35c57c7的情况数, 枚举下一个数是什么转移即可。
同理令 dp2(i,c2,c3,c5,c7) d p 2 ( i , c 2 , c 3 , c 5 , c 7 ) 表示考虑右边n个数中到第 i i 个数为止积为2c23c35c57c7的情况数.

最终答案就是 c2,c3,c5,c7dp1(n,c2,c3,c5,c7)×dp2(n,c2,c3,c5,c7) ∑ c 2 , c 3 , c 5 , c 7 d p 1 ( n , c 2 , c 3 , c 5 , c 7 ) × d p 2 ( n , c 2 , c 3 , c 5 , c 7 )
注意在统计最终答案时要用高精度,以及空间限制 64 64 MB需要使用滚动数组。
时间复杂度 O(60n5) O ( 60 n 5 )

#include<bits/stdc++.h>
#define LL long long
#define ull unsigned long long
#define ULL ull
#define mp make_pair
#define pii pair<int,int>
#define piii pair<int, pii >
#define pll pair <ll,ll>
#define pb push_back
#define big 20160116
#define INF 2147483647
#define pq priority_queue
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
namespace Mymath{
    LL qp(LL x,LL p,LL mod){
        LL ans=1;
        while (p){
            if (p&1) ans=ans*x%mod;
            x=x*x%mod;
            p>>=1;
        }
        return ans;
    }
    LL inv(LL x,LL mod){
        return qp(x,mod-2,mod);
    }
    LL C(LL N,LL K,LL fact[],LL mod){
        return fact[N]*inv(fact[K],mod)%mod*inv(fact[N-K],mod)%mod;
    }
    template <typename Tp> Tp gcd(Tp A,Tp B){
        if (B==0) return A;
        return gcd(B,A%B);
    }
    template <typename Tp> Tp lcm(Tp A,Tp B){
        return A*B/gcd(A,B);
    }
};
namespace fwt{
    using namespace Mymath;
    void FWT(int a[],int n,LL mod)
    {
        for(int d=1;d<n;d<<=1)
            for(int m=d<<1,i=0;i<n;i+=m)
                for(int j=0;j<d;j++)
                {
                    int x=a[i+j],y=a[i+j+d];
                    a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;
                    //xor:a[i+j]=x+y,a[i+j+d]=x-y;
                    //and:a[i+j]=x+y;
                    //or:a[i+j+d]=x+y;
                }
    }

    void UFWT(int a[],int n,LL mod)
    {
        LL rev=inv(2,mod);
        for(int d=1;d<n;d<<=1)
            for(int m=d<<1,i=0;i<n;i+=m)
                for(int j=0;j<d;j++)
                {
                    int x=a[i+j],y=a[i+j+d];
                    a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;
                    //xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;
                    //and:a[i+j]=x-y;
                    //or:a[i+j+d]=y-x;
                }
    }
    void solve(int a[],int b[],int n,LL mod)
    {
        FWT(a,n,mod);
        FWT(b,n,mod);
        for(int i=0;i<n;i++) a[i]=1LL*a[i]*b[i]%mod;
        UFWT(a,n,mod);
    }
};
const int Maxn=55;
string s;
LL dp[2][58][40][21][21];
LL A[58][40][21][21],B[58][40][21][21];
LL p10[19];
LL C(LL n,LL k){
    LL ans=1;
    for (int i=n;i>=n-k+1;i--){
        ans=ans*i/(n+1-i);
    }
    return ans;
}
int cst[15][15];
const int Maxk=105;
string mul(string a,string b){
    int res[Maxk];
    memset(res,0,sizeof(res));
    reverse(a.begin(),a.end());
    reverse(b.begin(),b.end());
    for (int i=0;i<a.length();i++){
        for (int j=0;j<b.length();j++){
            res[i+j]+=(a[i]-'0')*(b[j]-'0');
        }
    }
    for (int i=0;i<Maxk;i++){
        if (res[i]>=10) {
            res[i+1]+=(res[i]/10);
            res[i]%=10;
        }
    }
    string ret;
    bool flag=false;
    for (int i=Maxk-1;i>=0;i--){
        if (flag || res[i]){
            flag=true;
            ret=ret+(char)(res[i]+'0');
        }
    }
    if (ret=="") ret="0";
    return ret;
}
string add(string a,string b){
    if (a.length()<b.length()) swap(a,b);
    while (a.length()!=b.length()){
        b='0'+b;
    }
    for (int i=a.length()-1;i>=0;i--){
        a[i]+=(b[i]-'0');
        if (a[i]>'9' && i){
            a[i]-=10;
            a[i-1]++;
        }
    }
    if (a[0]>'9'){
        a[0]-=10;
        a='1'+a;
    }
    return a;
}
string minuss(string a,string b){
    //if (a.length()<b.length()) swap(a,b);
    while (a.length()!=b.length()){
        b='0'+b;
    }
    for (int i=a.length()-1;i>=0;i--){
        a[i]-=(b[i]-'0');
    }
    for (int i=a.length()-1;i>=0;i--){
        if (a[i]<'0'){
            a[i]+=10;
            a[i-1]--;
        }
    }
    while (a[0]=='0') a=a.substr(1);
    return a;
}
string tostr(LL x){
    string r;
    while (x){
        r+=(char)(x%10+'0');
        x/=10;
    }
    reverse(r.begin(),r.end());
    return r;
}
int main(){
    freopen("banal.in","r",stdin);
    freopen("banal.out","w",stdout);
    cst[2][2]=1;
    cst[3][3]=1;
    cst[4][2]=2;
    cst[5][5]=1;
    cst[6][2]=cst[6][3]=1;
    cst[7][7]=1;
    cst[8][2]=3;
    cst[9][3]=2;
    int n;
    p10[0]=1;
    for (int i=1;i<=18;i++){
        p10[i]=p10[i-1]*10;
    }
    cin>>n;
    cin>>s;
    string a,b;
    a=s.substr(0,n);b=s.substr(n);
    bool a0=false,b0=false;
    int cc=0,ca=0,cb=0;
    for (int i=0;i<s.size();i++) if (s[i]=='?') cc++;
    for (int i=0;i<n;i++) a0|=(a[i]=='0');
    for (int i=0;i<n;i++) if (a[i]=='?')  ca++;
    cb=cc-ca;
    for (int i=0;i<n;i++) b0|=(b[i]=='0');
    if (a0 && b0){
        printf("%s\n0\n",mul(tostr(p10[ca]),tostr(p10[cb])).c_str());
        return 0;
    }
    if (a0 && !b0){
        LL coef=p10[ca];
        LL bad=0;int coo=1;
        for (int j=0;j<=cb;j++){
            bad+=coo*C(cb,j)*p10[cb-j];
            coo=-coo;
        }
        LL good=p10[cb]-bad;
        string r1=mul(tostr(good),tostr(coef));
        string r2=mul(tostr(bad),tostr(coef));
        printf("%s\n%s\n",r1.c_str(),r2.c_str());
        return 0;
    }
    if (!a0 && b0){
        LL coef=p10[cb];
        LL bad=0;
        int coo=1;
        for (int j=0;j<=ca;j++){
            bad+=coo*C(ca,j)*p10[ca-j];
            coo=-coo;
        }
        LL good=p10[ca]-bad;
        string r1=mul(tostr(good),tostr(coef));
        string r2=mul(tostr(bad),tostr(coef));
        printf("%s\n%s\n",r1.c_str(),r2.c_str());
        return 0;
    }
    dp[0][0][0][0][0]=1;
    for (int ii=0;ii<n;ii++){
        int i=ii&1;
        for (int c2=0;c2<=54;c2++){
            for (int c3=0;c3<=37;c3++){
                for (int c5=0;c5<=18;c5++){
                    for (int c7=0;c7<=18;c7++){
                        dp[i^1][c2][c3][c5][c7]=0;
                    }
                } 
            }
        }
        for (int c2=0;c2<=54;c2++){
            for (int c3=0;c3<=37;c3++){
                for (int c5=0;c5<=19;c5++){
                    for (int c7=0;c7<=19;c7++){
                        if (dp[i][c2][c3][c5][c7]==0) continue;
                        if (a[ii]!='?'){
                            int v=a[ii]-'0';
                            dp[i^1][c2+cst[v][2]][c3+cst[v][3]][c5+cst[v][5]][c7+cst[v][7]]+=dp[i][c2][c3][c5][c7];
                        }
                        else{
                            for (int v=1;v<=9;v++){
                                dp[i^1][c2+cst[v][2]][c3+cst[v][3]][c5+cst[v][5]][c7+cst[v][7]]+=dp[i][c2][c3][c5][c7];
                            }
                        }
                    }
                }
            }
        }
    }
    for (int c2=0;c2<=54;c2++){
        for (int c3=0;c3<=37;c3++){
            for (int c5=0;c5<=18;c5++){
                for (int c7=0;c7<=18;c7++){
                    A[c2][c3][c5][c7]=dp[n&1][c2][c3][c5][c7];
                }
            } 
        }
    }
    memset(dp,0,sizeof(dp));
    dp[0][0][0][0][0]=1;
    for (int ii=0;ii<n;ii++){
        int i=ii&1;
        for (int c2=0;c2<=54;c2++){
            for (int c3=0;c3<=37;c3++){
                for (int c5=0;c5<=18;c5++){
                    for (int c7=0;c7<=18;c7++){
                        dp[i^1][c2][c3][c5][c7]=0;
                    }
                } 
            }
        }
        for (int c2=0;c2<=54;c2++){
            for (int c3=0;c3<=37;c3++){
                for (int c5=0;c5<=19;c5++){
                    for (int c7=0;c7<=19;c7++){
                        if (dp[i][c2][c3][c5][c7]==0) continue;
                        if (b[ii]!='?'){
                            int v=b[ii]-'0';
                            dp[i^1][c2+cst[v][2]][c3+cst[v][3]][c5+cst[v][5]][c7+cst[v][7]]+=dp[i][c2][c3][c5][c7];
                        }
                        else{
                            for (int v=1;v<=9;v++){
                                dp[i^1][c2+cst[v][2]][c3+cst[v][3]][c5+cst[v][5]][c7+cst[v][7]]+=dp[i][c2][c3][c5][c7];
                            }
                        }
                    }
                }
            }
        }
    }
    for (int c2=0;c2<=54;c2++){
        for (int c3=0;c3<=37;c3++){
            for (int c5=0;c5<=18;c5++){
                for (int c7=0;c7<=18;c7++){
                    B[c2][c3][c5][c7]=dp[n&1][c2][c3][c5][c7];
                }
            } 
        }
    }
    string good="0";
    for (int c2=0;c2<=54;c2++){
        for (int c3=0;c3<=37;c3++){
            for (int c5=0;c5<=18;c5++){
                for (int c7=0;c7<=18;c7++){
                    LL t1=A[c2][c3][c5][c7],t2=B[c2][c3][c5][c7];
                    if (t1>0 && t2>0){
                    //  cout<<c2<<c3<<c5<<c7<<endl;
                    //  P(t1*t2);
                        good=add(good,mul(tostr(t1),tostr(t2)));
                    }
                }
            } 
        }
    }
    //P(good);
    LL ba=0;
    LL ccc=1;
    for (int i=0;i<=ca;i++){
        ba+=ccc*C(ca,i)*p10[ca-i];
        ccc*=-1;
    }
    LL ga=p10[ca]-ba;
    //cout<<ba<<ga<<endl;
    LL bb=0;
    ccc=1;
    for (int i=0;i<=cb;i++){
        bb+=ccc*C(cb,i)*p10[cb-i];
        ccc*=-1;
    }
    LL gb=p10[cb]-bb;
    //cout<<ba<<ga<<endl;
    string rr=mul(tostr(ga),tostr(gb));
    rr=add(rr,good);
    //P(rr);
    //P(good);
    //rr+=good;
    string tot=mul(tostr(p10[ca]),tostr(p10[cb]));
    if (rr=="") rr="0";
    printf("%s\n",rr.c_str());
    string mn=minuss(tot,rr);
    if (mn=="") mn="0";
    printf("%s\n",mn.c_str());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值