2021暑假算法学习笔记(基础复习)#1
2021-07-06
过了一下基础算法,然后去做英文题拯救自己的阅读能力。
CodeForces-1513A Array and Peaks
本题阅读无障碍。
思路:一个1到n的顺序排列,当需要peak时直接交换相邻两个数即可,如下所示:
1,(2, 3),(4,5),(6,7),(8,9),10
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int t;
int n, k;
void print()
{
int t = 0;
printf("1 ");
for (int i = 2; i <= n; i ++ )
{
if (i % 2 == 0) t ++ ;//cnt_peak
if (t <= k)
{
if (i % 2 == 0) printf("%d ", i + 1);
else printf("%d%c", i - 1, i == n ? '\n' : ' ');
}
else printf("%d%c", i, i == n ? '\n' : ' ');
}
}
int main()
{
cin >> t;
while (t -- )
{
cin >> n >> k;
if (n % 2)//奇数
if (k > (n - 1) / 2)
{
puts("-1");
continue;
}
else
{
if (n == 1)
{
puts("1");
continue;
}
print();
}
else
{
if (k > (n - 2) / 2)
{
puts("-1");
continue;
}
else print();
}
}
return 0;
}
CodeForces-1511A Review Site
阅读无障碍。manipulate——操作
思路:直接统计1 和 3的个数就行
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int t;
int main()
{
scanf("%d", &t);
while (t -- )
{
int n, ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i ++ )
{
int x;
scanf("%d", &x);
if (x != 2) ans ++ ;
}
printf("%d\n", ans);
}
return 0;
}
CodeForces-4A Watermelon
berry——浆果
even——偶数的;同样大小的;平分的
obligatory——义务的;必须的;义不容辞的
#include <iostream>
using namespace std;
int w;
int main()
{
cin >> w;
if (w != 2 && w % 2 == 0) puts("Yes");
else puts("No");
return 0;
}
CodeForces-1513A Add One
思路1(tle):f[i, j]表示操作了j次,有f[i, j]个数字i,最后的答案就是f[i, m]求和,i从0到9。TLE。
tle code
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200010, MOD = 1e9 + 7;
int f[12][N];
int t;
int n, m;
int main()
{
scanf("%d", &t);
while (t -- )
{
scanf("%d%d", &n, &m);
for (int i = 0; i <= 9; i ++ ) f[i][0] = 0;
while (n)
{
f[n % 10][0] ++ ;
n /= 10;
}
for (int j = 1; j <= m; j ++ )
{
f[0][j] = f[9][j - 1] % MOD;
f[1][j] = (f[0][j - 1] + f[9][j - 1]) % MOD;
for (int i = 2; i <= 9; i ++ ) f[i][j] = f[i - 1][j - 1] % MOD;
}
long long ans = 0;
for (int i = 0; i <= 9; i ++ ) ans = (ans + f[i][m]) % MOD;
printf("%lld\n", ans);
}
return 0;
}
思考:一个样例最多2e5的操作次数,时间复杂度较高。我们可以知道每个数字经过若干次变换都会变成10,所以我们不妨预处理出来10这个序列操作若干次后的长度变换情况,然后之后只需要统计数字个数,然后直接调用预处理好的信息数组即可。
每次操作如果序列边长,那么增长的数量一定是上一步9的数量,所以用sum存储序列长度,并更新。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10, MOD = 1e9 + 7;
int f[N][15];//要预处理的数组
int a[15];//存储数字n的每一位
int sum[N];//存储变化i次目前长度变成了多少
int n, m;
int t;
void init()//预处理f数组
{
f[0][0] = f[0][1] = 1, sum[0] = 2;
for (int i = 1; i < N; i ++ )
{
int temp = f[i - 1][9];
for (int j = 9; j >= 1; j -- )
f[i][j] = f[i - 1][j - 1];
f[i][0] = temp;
f[i][1] = (1ll * f[i][1] + temp) % MOD;
sum[i] = (1ll * sum[i - 1] + temp) % MOD;
}
}
int main()
{
init();
scanf("%d", &t);
while (t -- )
{
scanf("%d%d", &n, &m);
//学习大佬博客学到的写法
a[0] = 0;//一个含义是a数组索引,另一个含义是统计数字位数
while (n)
{
a[ ++ a[0]] = n % 10;
n /= 10;
}
LL ans = 0;
for (int i = 1; i <= a[0]; i ++ )//看每一位
{
int cnt = 10 - a[i];//距离10差多少步
if (m < cnt)//不够分裂
ans = (1ll * ans + 1) % MOD;//加上这一位的长度
else
ans = (1ll * ans + sum[m - cnt]) % MOD;//加上这一位变换后的长度
}
printf("%lld\n", ans);
}
return 0;
}