您的位置:首页 > 其它

51Nod-1197-字符串的数量 V2

2016-10-16 18:07 441 查看
ACM模版

描述



题解

这道题好阔怕,在V1的讨论区有最牛逼的题解,Orz!!!

虽然有题解,有代码,可是由于代数还没有学,所以对部分有些懵逼,先Mark一下,过一阵子能力有所提升后好好瞅瞅喽……

提供两份代码,对于这道题,代码One和代码Two效率差距不明显,代码Two相比代码One多了一个预处理,针对V3的多组数据可以提高很多效率!!!

代码

One:

#include <stdio.h>

typedef long long ll;

const int MAXN = 61;
const int MOD = 1e9 + 7;

int deg;
int iact[MAXN + 1];
int val[MAXN + 1];
int nxt[MAXN + 1];
int seq[MAXN + 1];

ll n, m;

inline int mod_add(int x, int y)
{
return x + y < MOD ? x + y : x + y - MOD;
}

inline int mod_dec(int x, int y)
{
return x - y >= 0 ? x - y : x - y + MOD;
}

int value(int a)
{
if (a < deg)
{
return val[a];
}
static int pre[MAXN], suf[MAXN];
pre[0] = a;
for (int i = 1; i < deg; ++i)
{
pre[i] = (ll)(a - i) * pre[i - 1] % MOD;
}
suf[deg - 1] = a - deg + 1;
for (int i = deg - 2; i >= 0; --i)
{
suf[i] = (ll)(a - i) * suf[i + 1] % MOD;
}
int ret = 0;
for (int i = 0; i < deg; ++i)
{
int tmp = (ll)val[i] * iact[i] % MOD * iact[deg - 1 - i] % MOD;
if (i > 0)
{
tmp = (ll)tmp * pre[i - 1] % MOD;
}
if (i < deg - 1)
{
tmp = (ll)tmp * suf[i + 1] % MOD;
}
if (((deg - 1 - i) & 1) && tmp > 0)
{
tmp = MOD - tmp;
}
ret += tmp;
if (ret >= MOD)
{
ret -= MOD;
}
}
return ret;
}

struct Matrix
{
int r, c, num[MAXN][MAXN];
Matrix operator * (const Matrix &t) const
{
Matrix ret = {r, t.c};
for (int i = 0; i < r; ++i)
{
for (int j = 0; j < c; ++j)
{
for (int k = 0; k < t.c; ++k)
{
ret.num[i][k] = (ret.num[i][k] + (ll)num[i][j] * t.num[j][k]) % MOD;
}
}
}
return ret;
}
Matrix pow(ll k)
{
Matrix ret = {r, r}, tmp = *this;
for (int i = 0; i < r; ++i)
{
ret.num[i][i] = 1;
}
for (; k > 0; k >>= 1, tmp = tmp * tmp)
{
if (k & 1)
{
ret = ret * tmp;
}
}
return ret;
}
} A;

int main()
{
//    int T;
//    scanf("%d", &T);

//    while (T--)
//    {
iact[0] = 0;
iact[1] = 1;
for (int i = 2; i <= MAXN; ++i)
{
iact[i] = MOD - MOD / i * (ll)iact[MOD % i] % MOD;
}
iact[0] = 1;
for (int i = 1; i <= MAXN; ++i)
{
iact[i] = iact[i - 1] * (ll)iact[i] % MOD;
}

int len;
scanf("%lld%lld", &n, &m);

ll tmp = (n << 1) - 1;
deg = val[0] = 1;
for (len = 1; --tmp >= 0; ++len)
{
for (int i = 0, pos = tmp & 1; i <= deg; ++i, pos = mod_add(pos, 2))
{
nxt[i] = mod_add(i > 0 ? nxt[i - 1] : 0, value(pos));
}
++deg;
for (int i = 0; i < deg; ++i)
{
val[i] = nxt[i];
}
tmp >>= 1;
seq[len] = value(tmp % MOD);
}
--len;

ll tmp_ = n - 1;
deg = val[0] = 1;
for (int j = 1; --tmp_ >= 0; ++j)
{
for (int i = 0, pos = tmp_ & 1; i <= deg; ++i, pos = mod_add(pos, 2))
{
nxt[i] = mod_add(i > 0 ? nxt[i - 1] : 0, value(pos));
}
++deg;
for (int i = 0; i < deg; ++i)
{
val[i] = nxt[i];
}
tmp_ >>= 1;
seq[j] = mod_dec(seq[j], value(tmp_ % MOD));
}

A = (Matrix){len, len};
for (int i = 1; i < len; ++i)
{
A.num[i][i - 1] = 1;
}
for (int i = 0; i < len; ++i)
{
A.num[i][len - 1] = seq[len - i];
}
A = A.pow(m);
printf("%d\n", A.num[len - 1][len - 1]);
//    }

return 0;
}


Two:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;

typedef long long ll;

const int MOD = 1e9 + 7;
const int MAXN = 63;

void add(ll &x, ll y)
{
x += y;
if (x >= MOD)
{
x -= MOD;
}
}

ll i, j;
ll p, k;
ll MAXP;
ll A[MAXN + 5][MAXN + 5];
ll E[MAXN + 5];
ll pr[20005];
ll MA[20005];

vector<ll> v[MAXN];
vector<ll> va[MAXN];
vector<ll> vb[MAXN];
vector<ll> vr[MAXN];

ll modAdd(ll a, ll b)
{
a += b;
return a >= MOD ? (a - MOD) : a;
}

ll modMul(ll a , ll b)
{
a *= b;
return a >= MOD ? (a % MOD) : a;
}

void multiply(const vector<ll> &Q, vector<ll> &Qr)
{

int size = (int)Qr.size();

for (int i = 0 ; i < size; i++)
{
Qr[i] = 0;
for (int j = max(0 , 2 * i - size + 1); j < min(size, (2 * i + 1)); j++)
{

ll x = (j & 1) ? ((MOD - Q[j])) : (Q[j]);
ll y = modMul(x, Q[2 * i - j]);

Qr[i] = modAdd(Qr[i], y);
}
}
}

void cal(ll *A, ll n, ll k, ll *C)
{
vector<ll> Q(k + 3);
vector<ll> Qr(k + 3);

n--;
while (n >= k)
{
Q[0] = 1;
for (ll i = 0; i < k; i++)
{
Q[i + 1] = -C[i];
if (Q[i + 1] < 0)
{
Q[i + 1] += MOD;
}
}

for (ll i = k; i < (2 * k); i++)
{
A[i] = 0;
for (ll j = 0; j < k; j++)
{
ll add = modMul(A[i - 1 - j], C[j]);
A[i] = modAdd(A[i], add);
}
}

multiply(Q, Qr);

for (ll i = 0; i < k; i++)
{
C[i] = (-Qr[i + 1]);

if (C[i] < 0)
{
C[i] += MOD;
}
}

int offset = n & 1;
for (ll i = 0; i < k; i++)
{
A[i] = A[2 * i + offset];
}

n /= 2;
}

printf("%lld\n", A
);
}

int power(ll x, ll y)
{
int sum = 1;
for (; y; y >>= 1)
{
if (y & 1)
{
sum = 1ll * sum * x % MOD;
}
x = 1ll * x * x % MOD;
}
return sum;
}

void guass(ll n)
{
for (int i = 1; i <= n; ++i)
{
int j;
for (j = i; j <= n; ++j)
{
if (A[j][i])
{
break;
}
}
for (int k = 1; k <= n + 1; ++k)
{
swap(A[i][k], A[j][k]);
}
int p = power(A[i][i], MOD - 2);
for (int j = i + 1; j <= n; ++j)
{
if (A[j][i])
{
int now = 1ll * A[j][i] * p % MOD;
for (int k = i; k <= n + 1; ++k)
{
add(A[j][k], MOD - 1ll * A[i][k] * now % MOD);
}
}
}
}
for (ll i = n; i; --i)
{
for (ll j = i + 1; j <= n; ++j)
{
add(A[i][n + 1], MOD - 1ll * A[i][j] * E[j] % MOD);
}
E[i] = 1ll * A[i][n + 1] * power(A[i][i], MOD - 2) % MOD;
}
}

long long n, m, sA[MAXN], sB[MAXN];

long long Count(vector<ll> A, ll R)
{
ll i, j, sum = 0;
R %= MOD;
for (i = 0; i < A.size(); ++i)
{
ll S = 0, now = 1;
for (j = 0; j < vr[i].size(); ++j)
{
add(S, 1ll * vr[i][j] * now % MOD), now = 1ll * now * R % MOD;
}
add(sum, 1ll * S * A[i] % MOD);
}
return sum;
}

int main()
{
for (i = 0; i < MAXN; ++i)
{
memset(A, 0, sizeof(A));
for (j = 1; j <= i + 2; ++j)
{
for (k = 1; k <= i + 2; ++k)
{
A[j][k] = power(j, k - 1);
}
A[j][i + 3] = power(2 * j - 1, i);
add(A[j][i + 3], A[j - 1][i + 3]);
if (j > 1)
{
add(A[j][i + 3], power(2 * j - 2, i));
}
}
guass(i + 2);
for (j = 1; j <= i + 2; ++j)
{
v[i].push_back(E[j]);
}
}

for (i = 0; i < MAXN; ++i)
{
memset(A, 0, sizeof(A));
for (j = 1; j <= i + 2; ++j)
{
for (k = 1; k <= i + 2; ++k)
{
A[j][k] = power(j, k - 1);
}
A[j][i + 3] = power(j, i);
(A[j][i + 3] += A[j - 1][i + 3]) %= MOD;
}
guass(i + 2);
for (j = 1; j <= i + 2; ++j)
{
vr[i].push_back(E[j]);
}
}
//    int T;
//    scanf("%d", &T);
//    for (; T--; )
//    {
scanf("%lld%lld", &n, &m);
MAXP = (int)(log2(n) + 1);
memset(sA, 0, sizeof(sA));
memset(sB, 0, sizeof(sB));
for (i = 1; i <= MAXP; ++i)
{
va[i].clear(), vb[i].clear();
}
sA[1] = n / 2;
sB[1] = n;
vb[1].push_back(1);
for (i = 2; i <= MAXP; ++i)
{
sA[i] = sA[i - 1] / 2;
sB[i] = sB[i - 1] / 2;
long long str = Count(vb[i - 1], sB[i - 1]);
for (j = 0; j < i; ++j)
{
vb[i].push_back(0), va[i].push_back(0);
}
vb[i][0] = str;
for (j = 0; j < vb[i - 1].size(); ++j)
{
ll wei = (MOD - vb[i - 1][j]);
for (k = 0; k < (int)v[j].size(); ++k)
{
add(vb[i][k], 1ll * wei * v[j][k] % MOD);
}
}
ll End = Count(vb[i - 1], sA[i - 1]);
va[i][0] = (str - End + MOD) % MOD;
add(va[i][0], Count(va[i - 1], sA[i - 1]));
for (j = 0; j < va[i - 1].size(); ++j)
{
ll wei = (MOD - va[i - 1][j]);
for (k = 0; k < v[j].size(); ++k)
{
add(va[i][k], 1ll * wei * v[j][k] % MOD);
}
}
}
for (i = 1; i <= MAXP; ++i)
{
pr[i] = Count(va[i], sA[i]);
add(pr[i], Count(vb[i], sB[i]));
add(pr[i], MOD - Count(vb[i], sA[i]));
}
memset(MA, 0, sizeof(MA));
MA[0] = 1;
for (i = 1; i < MAXP; ++i)
{
for (j = 1; j <= i; ++j)
{
add(MA[i], 1ll * MA[i - j] * pr[j] % MOD);
}
}
for (i = 0; i < MAXP; ++i)
{
swap(pr[i], pr[i + 1]);
}
if (m < MAXP)
{
printf("%lld\n", MA[m]);
}
else
{
cal(MA, m + 1, MAXP, pr);
}
//    }

return 0;
}


参考

51Nod 1196 字符串的数量
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp 问题残余 数论