明天F补完题就加上()
放假了又能网瘾漏w
上周的abc太简单了这周的好难,E出了个数位dp想法以为是想复杂了结果还真是...
Tasks - AtCoder Beginner Contest 336
题意:
输出龙的拼音,把'o'换成连续的n个'o'
代码:
void solve()
{
int n;
scanf("%d", &n);
printf("L");
while (n--)printf("o");
printf("ng\n");
}
题意:
输出n的二进制表示末尾有多少个连续的0
代码:
直接bitset偷懒了
void solve()
{
int x;
scanf("%d", &x);
bitset<40>st = x;
for (int i = 0;; ++i)
{
if (st[i] != 0)
{
printf("%d", i);
return;
}
}
}
题意:
输出仅由偶数构成的十进制数中第k小的数
题解:
看成五进制即可,记得特判n=1的情况
void solve()
{
LL n;
scanf("%lld", &n);
vectorans;
--n;
if (n == 0)
{
printf("0");
return;
}
while (n)
{
ans.push_back(n % 5);
n /= 5;
}
while (ans.size())
{
printf("%d", ans.back() * 2);
ans.pop_back();
}
}
题意:
给出一个长度为n的正整数数组,你可以进行以下两种操作:
1:将一个元素-1
2:在数组开头或者末尾删除一个元素
使得数组最终变成1,2,3,...,k-1,k,k-1,...,3,2,1的形式,求可能的最大的k
题解:
把每个ai想象成高度,找最大的k相当于是在这个图里找一个最大的金字塔形的东西,例如样例1:
22311 121
#
### -> #
##### ###
l[i]表示点i在左斜边上时i位置的最大高度,转移为l[i] = min(l[i - 1] + 1, a[i]),r[i]同理,答案为max({ min(l[i], r[i]) }),具体做法见代码
int a[N], l[N], r[N];
void solve()
{
int n, ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for (int i = 1, j = n; i <= n; ++i, --j)
{
l[i] = min(l[i - 1] + 1, a[i]);
r[j] = min(r[j + 1] + 1, a[j]);
}
for (int i = 1; i <= n; ++i)
ans = max(ans, min(l[i], r[i]));
printf("%d\n", ans);
}
题意:
一个数的数位和为他的十进制表示上的所有数的和,当一个数能被他的数位和整除我们成这个数是好的数,求从0到n一共有多少个好的数
题解:
先枚举所有可能的数位和,对于每个数位和m我们做一个dp求数位和为m且能被m整除的小于等于n的数的数量:
设dp[i][j][k]为对于十进制数的前i位,数位和为j,该数当前的值取模m后的余数为k时的方案数,对于每个确定的dp[i][j][k],它转移到下一位时,设下一位填入的数为x,转移为:dp[i - 1][j + x][(k + x * pow(10, i - 1) % m] += dp[i][j][k],关于限制当前数小于等于n,我们只需要在求完每一位数之后把超过n的部分减去即可。大致思路是这样,具体做法见代码
题解中的数位和我在代码中用的是剩余的数位和,思路是一样的就是和题解中的转移j要反一下
LL pw[20], dp[16][140][140];
void solve()
{
LL n, ans = 0;
scanf("%lld", &n);
LL t = n, mx = 0;
vectora;
while (t)
mx += t % 10, a.push_back(t % 10), t /= 10;
mx = max(mx, a.back() - 1 + ((LL)a.size() - 1) * 9);
pw[0] = 1;
for (int i = 1; i < 20; ++i)
pw[i] = pw[i - 1] * 10;
for (int m = 1; m <= mx; ++m)//枚举数位和m
{
LL s = m, md = 0;//按n的每一位选数时的数位和和余数
memset(dp, 0, sizeof dp);
dp[a.size()][m][0] = 1;
for (int i = a.size(); i > 0; --i)//第i位,准备填第i-1位
{
for (int j = 0; j <= m; ++j)//填数前数位和还剩j
{
for (int k = 0; k < m; ++k)//余数是k
{
for (int x = 0; x <= 9 && j - x >= 0; ++x)//第i-1位填x的转移
dp[i - 1][j - x][(k + x * pw[i - 1]) % m] += dp[i][j][k];
}
}
//减去超过上界的
for (int x = a[i - 1] + 1; x <= 9 && s - x >= 0; ++x)
{
int j = s, k = md;
dp[i - 1][j - x][(k + x * pw[i - 1]) % m] -= 1;
}
s -= a[i - 1], md = (md + a[i - 1] * pw[i - 1]) % m;
}
ans += dp[0][0][0];
}
printf("%lld\n", ans);
}
写的挺抽象的,应该还有更好的做法