[HAOI 2010] 计数

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=2425

[算法]

        类似与数位动态规划的思想 , 用组合数学进行简单推导即可

        时间复杂度 : O(L ^ 3)

[代码]

        

#include<bits/stdc++.h>
using namespace std;
#define N 110
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;

#define int ll

int L , L0;
int tmp[N] , digit[N] , cnt[N];
char s[N];

template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
template <typename T> inline void read(T &x)
{
   T f = 1; x = 0;
   char c = getchar();
   for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
   for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
   x *= f;
}
inline ll quickpow(ll a , int n)
{
    ll b = a , res = 1;
    while (n > 0)
    {
        if (n & 1) res *= b;    
        b = b * b;
        n >>= 1;
    }    
    return res;
}
inline void add(int x , int val)
{
    for (int i = 2; i <= (int)sqrt(x); i++)
    {
        if (x % i == 0)
        {
            while (x % i == 0)
            {
                tmp[i] += val;
                x /= i;
            }
        }
    }
    if (x > 1) tmp[x] += val;
}

signed main()
{
    
    scanf("%s" , s + 1);
    L = strlen(s + 1);
    for (int i = 1; i <= L; i++)
    {
        if (s[i] > '0') ++L0;
        ++cnt[s[i] - '0'];
        digit[i] = s[i] - '0';
    }
    ll ans = 0;
    for (int k = 1; k < L;k++) 
    {
        if (k < L0) continue;
        memset(tmp , 0 , sizeof(tmp));
        for (int i = 1; i <= L0; i++) add(i , 1);
        for (int i = 1; i <= 9; i++)
        {
            for (int j = 1; j <= cnt[i]; j++)
            {
                add(j , -1);
            }    
        }    
        for (int i = 1; i <= k - 1; i++) add(i , 1);
        for (int i = 1; i <= L0 - 1; i++) add(i , -1);
        for (int i = 1; i <= k - L0; i++) add(i , -1);
        ll cont = 1;
        for (int i = 1; i <= 100; i++) cont *= quickpow(i , tmp[i]);
        ans += cont;
    }
    for (int i = 1; i <= L; i++)
    {
        for (int j = 0; j < digit[i]; j++)
        {
            if (i == 1 && !j) continue;
            if (!j || cnt[j] > 0)
            {
                --cnt[j];
                int nowcnt = 0;
                for (int k = 1; k <= 9; k++) nowcnt += cnt[k];
                if (nowcnt > L - i) 
                {                
                    ++cnt[j];
                    continue;
                }
                memset(tmp , 0 , sizeof(tmp));
                for (int k = 1; k <= nowcnt; k++) add(k , 1);
                for (int x = 1; x <= 9; x++)
                {
                    for (int y = 1; y <= cnt[x]; y++)
                    {
                        add(y , -1);
                    }
                }
                for (int k = 1; k <= L - i; k++) add(k , 1);
                for (int k = 1; k <= nowcnt; k++) add(k , -1);
                for (int k = 1; k <= L - i - nowcnt; k++) add(k , -1);
                ll cont = 1;
                for (int k = 1; k <= 100; k++) cont *= quickpow(k , tmp[k]);
                ans += cont;
                ++cnt[j];    
            }    
        }    
        --cnt[digit[i]];
    }
    printf("%lld\n" , ans);
    
    return 0;
}

 

posted @ 2019-02-07 22:34  evenbao  阅读(135)  评论(0编辑  收藏  举报