前言:
突然发现数位dp挺好用.
T1 Bomb
题意:
给你几个数,输出0-n之间含”49”的数的数量.
解析:
预处理出含49的数就行.
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL dp[25][1000];
void chu()
{
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
int i;
for (i = 1; i <= 22; i++)
dp[i][0] = dp[i - 1][0] * 10 - dp[i - 1][1], dp[i][1] = dp[i - 1][0], dp[i][2] = dp[i - 1][2] * 10 + dp[i - 1][1];
}
LL solve(LL n)
{
LL i, gg = n, len = 0, a[25], flag = 0, ans = 0;
while (n)
{
a[++len] = n % 10;
n /= 10;
}
a[len + 1] = 0;
for (i = len; i; i--)
{
ans += dp[i - 1][2] * a[i];
if (flag)
ans += dp[i - 1][0] * a[i];
if (!flag && a[i] > 4)
ans += dp[i - 1][1];
if (a[i + 1] == 4 && a[i] == 9)
flag = 1;
}
return ans;
}
int main()
{
int t;
LL n;
scanf("%d", &t);
chu();
while (t--)
{
scanf("%lld", &n);
printf("%lld\n", solve(n + 1));
}
return 0;
}
提示:
暴力会超时.
出处:
T2 Little Elephant and Elections
题意:
规定4,7为lucky数。给一个数m,求1~m中的七个数字的排列中,满足下列条件的排>列有多少个:
第七个数中含有的lucky数的数量大于前六个含有的lucky数的总和。(比如说>1234567,该数字有一个4,一个7,则他的lucky值为2)。
解析:
也是预处理.
代码:
#include <iostream>
#include <cmath>
#define NN 1000000007
using namespace std;
int n, t, s, k, a[20], lim;
long long c[110][100], f[20], anss;
long long dfs(int d, int w)
{
long long anss = 0;
if (d >= 6)
return 1;
for (int i = 0; i < lim - w; i++)
{
f[i]--;
anss = (anss + (f[i] + 1) * dfs(d + 1, w + i) % NN) % NN;
f[i]++;
}
return anss;
}
int main()
{
cin >> n;
t = n;
while (t)
{
a[k] = t % 10;
k++;
t /= 10;
}
for (int i = 0; i < 100; i++)
for (int j = 0; j < i + 1; j++)
{
c[i][j] = (i && j) ? (c[i - 1][j - 1] + c[i - 1][j]) % NN : 1;
}
for (int i = k - 1; i >= 0; i--)
{
for (int j = 0; j < a[i]; j++)
for (int l = 0; l < i + 1; l++)
{
f[l + s + (j == 4 || j == 7)] += c[i][l] * (1 << (3 * i - 2 * l));
}
s += (a[i] == 4 || a[i] == 7);
}
f[s]++, f[0]--;
for (int i = 1; i <= k; i++)
{
lim = i;
anss = (anss + dfs(0, 0) * f[i]) % NN;
}
cout << anss << endl;
return 0;
}
提示:
没有提示.
出处:
T4 Igor and Interesting Numbers
题意:
给出整数k和t,需要产生一个满足以下要求的第k个十六进制数
即十六进制数每一位上的数出现的次数不超过t.
解析:
暴力预处理.
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 200;
LL mm[maxn][maxn], dp[16][maxn];
int num[16], t;
LL k;
LL solve(int len)
{
memset(dp, 0, sizeof(dp));
for (int i = 0; i <= num[0]; i++)
dp[0][i] = mm[len][i];
for (int i = 1; i < 16; i++)
for (int l = 0; l <= len; l++)
for (int j = 0; j <= min(num[i], l); j++)
dp[i][l] += dp[i - 1][l - j] * mm[len - l + j][j];
return dp[15][len];
}
void print(int j)
{
if (j < 10)
cout << j;
else
cout << (char)(j + 'a' - 10);
}
void f(int len)
{
for (int i = len; i > 0; i--)
{
if (i == 1)
{
for (int j = 0; j < 16; j++)
{
if (j == 0 && len == 1)
continue;
if (num[j] != 0)
k--;
if (k == 0)
{
print(j);
break;
}
}
break;
}
for (int j = 0; j < 16; j++)
{
if (i == len && j == 0)
continue;
num[j]--;
LL tmp = solve(i - 1);
if (k > tmp)
k -= tmp;
else
{
print(j);
break;
}
num[j]++;
}
}
}
int main()
{
for (int i = 0; i < maxn; i++)
mm[i][0] = 1;
for (int i = 1; i < maxn; i++)
for (int j = 1; j <= i; j++)
mm[i][j] = mm[i - 1][j] + mm[i - 1][j - 1];
cin >> k >> t;
for (int i = 0; i < 16; i++)
num[i] = t;
int len = 1;
for (;; len++)
{
LL tmp = 0;
if (len == 1)
tmp = 15;
else
for (int j = 1; j < 16; j++)
{
num[j]--;
tmp += solve(len - 1);
num[j]++;
}
if (k > tmp)
k -= tmp;
else
break;
}
f(len);
return 0;
}
提示:
不知道.
出处:
T5 Palindromic Numbers
题意:
求[a,b]中回文数的个数
解析:
又是预处理.
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define LL long long
LL dp[30][30][2];
int num[30], temp[30];
LL dfs(int qi, int wei, bool shi, bool mm)
{
if (wei < 0)
return shi;
if (!mm && dp[qi][wei][shi] != -1)
return dp[qi][wei][shi];
int maxnn = mm ? num[wei] : 9;
LL anss = 0;
for (int i = -0; i <= maxnn; i++)
{
temp[wei] = i;
if (qi == wei && i == 0)
anss += dfs(qi - 1, wei - 1, shi, mm && i == maxnn);
else if (shi && wei < (qi + 1) / 2)
anss += dfs(qi, wei - 1, temp[qi - wei] == i, mm && i == maxnn);
else
anss += dfs(qi, wei - 1, shi, mm && i == maxnn);
}
if (!mm)
dp[qi][wei][shi] = anss;
return anss;
}
LL f(LL n)
{
int len = 0;
while (n)
{
num[len++] = n % 10;
n /= 10;
}
num[len] = 0;
return dfs(len - 1, len - 1, 1, 1);
}
int main()
{
int T, flag = 1;
scanf("%d", &T);
memset(dp, -1, sizeof(dp));
while (T--)
{
LL x, y;
scanf("%lld%lld", &x, &y);
if (x > y)
swap(x, y);
printf("Case %d: %lld\n", flag++, f(y) - f(x - 1));
}
return 0;
}
提示:
再见.