Tony's Log

Algorithms, Distributed System, Machine Learning

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

An ACM-level problem because it involves "advanced maths". It should not be marked as "Moderate". Other than that, it is a medium level DP one.

*Math modeling in your mind: can you see through the problem statement and figure out that it isa DP-style letter choice process? I couldn't.. This is so crucial, however.

*DP Part: there is dependency between letters: you should pick higher chars then lower chars, and DP choice occurs during this process.

*Maths Part: C(m + n, n) is used, but the numbers are huge, so regular combination formula is not working here. Lucas Theorem is necessary here (http://en.wikipedia.org/wiki/Lucas%27_theorem), which I will try to understand later..

I checked Editorials, understand it and then rewrite their Jave code into my solution in C++ (it looks almost the same).

#include <cmath>
#include <cstdio>
#include <vector>
#include <map>
#include <set>
#include <unordered_set>
#include <string>
#include <climits>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
using namespace std;

#define MAX_LEN 2501
#define MOD 1000003
/*
    Lucas Theorem: to compute large number of C(m, n)
 */
class compute {
    long long Fact[MOD], rFact[MOD];
public:
    void init(){
        Fact[0] = rFact[0] = 1;
        for (long i = 1; i < MOD; i++) {
            Fact[((int)i)] = (i * Fact[((int)(i - 1))]) % MOD;
            rFact[((int)i)] = powmod(Fact[((int)i)], MOD - 2);
        }
    }
    long long ways(long k, long n, long r){
        return lucas(n - k*(r - 1), r);
    }
    long long nCr(long n, long k) {
        if (n<0 || k<0 || k>n) return 0;
        return (((Fact[(int)n] * rFact[(int)k]) % MOD) *rFact[(int)(n - k)]) % MOD;
    }
    long long lucas(long n, long r) {
        if (n < MOD) return nCr(n, r);
        return (nCr(n / MOD, r / MOD) * nCr(n%MOD, r%MOD)) % MOD;
    }
    long long powmod(long b, long p) {
        long long ret = 1, a = b%MOD;
        while (p>0) {
            if (p % 2 == 1) ret = (ret*a) % MOD;
            a = (a*a) % MOD;
            p >>= 1;
        }
        return ret;
    }
};

compute cp;

///////////////////////
vector<int> howMany(26);

long long call(int pos, int taken, int n, int k, vector<vector<long>> &dp)
{
    if (pos > 25) return 1;
    if (dp[pos][taken] != -1)
        return dp[pos][taken];

    long long ret = call(pos + 1, taken, n, k, dp);

    for (int i = 1; i <= howMany[pos]; i++)
    {
        if ((i + taken) > n)
            break;
        long long curr = cp.ways(k, n - taken, i) *    call(pos + 1, taken + i, n, k, dp);
        curr %= MOD;
        ret += curr;
        if (ret >= MOD) 
            ret -= MOD;
    }
    dp[pos][taken] = ret;
    return ret;
}

int main()
{
    int n, k; cin >> n >> k;
    char buf[MAX_LEN] = {0};
    scanf("%s", buf);
    string s(buf);
    size_t len = s.length();

    vector<vector<long>> dp(26, vector<long>(len + 2, -1));
    for(char c : s)
        howMany[c - 'A'] ++;

    cp.init();
    long long ret = call(0, 0, n, k, dp);
    cout << ret << endl;

    return 0;
}
View Code
posted on 2015-05-19 10:53  Tonix  阅读(267)  评论(0编辑  收藏  举报