把过去和现在的笔记记录也搬了过来,也算是给以后留个念想吧,想想一开始打acm就是图一乐,后来发现这游戏还挺上头的,也算是度过了一段电竞生涯(xs)
早些时候的笔记写的好中二,连我自己看着都羞耻。
不过,就喜欢这种羞耻的感觉。
收录的题目大部分是个人认为质量不错的题目,以DP为主,非DP的题目都用※进行了标识。
当然,有些题解思路本身也是源自其他人的,不过除非特殊标注,否则都是用的自己的代码。

题目大意:

CF 1646E Power Board
题目大意:给一个大小为n,m的board(规模都为1e6),其中第i,j格的数为i^j,问这个board里有多少种数。

解:

第一行全是1,不用管。
之后开始就会出现重复了,可以看到2^2=4这种常见的重复类型,很容易就能推出来,当a^b=c^d的时候,c和a一定是同一个数的k次幂(注意,并不一定a是c的k次幂,血的教训)。也就是说对于每个i来讲,它都是有其源头的,而那个源头则是没有源头的,比如说2,它无法表示成除自己以外任何数的幂。根据因式分解的思路可以发现,不同源的数衍生出的数彼此是无法相等的
那么就拿2举例,2的这行有2^1,2^2,…,2^m,2^2的一行也有2^2^1,2^2^2,…以此类推。到了最后2这个数已经无所谓了,只要后面的次数相同就表示数字相同,而这个次数是j和目标行对于源的次数的成绩。
我们可以把形如
2 4 8 16 32
4 16 64 256 1024
8 64 512 4096 40968
这样的矩阵转化为
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
注意到了这个阶段,我的不重复数字个数就已经彻底和作为源的那个“2”没有关系了,由于宽度m是固定的,唯一会影响结果的其实也就是高度了。
那么高度会是多少呢,是源的1,2,3…n次幂,那么很显然,即使源是最小的2,在1e6的范围内这个高度最高也只有19,换句话说,我们可以通过19
1e6的复杂度把每个高度对应的不同数字个数暴力计算出来。
之后去遍历所有的源,计算出其对应矩阵高度然后直接加上算出的值就完了,然后在加上一个1。
这里其实是重复子问题(不同源但高度相同的数对应不同数字个数相同,而且不会与其它源重复),隐藏的特别巧妙啊,相当有意思的题。
你说它是dp吧,它没有状态转移,归类于基于找规律的暴力吧,碰到这种题得不出结论就把数字全print出来找规律好了。

代码

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
#include <istream>
#include <map>
#include <cmath>
#include <stack>
#include <set>
#include <cstring>
#include <string>
#define ll long long
#define maxn 200005
#define mdl 998244353
#define clr(a,n) for(int i=0;i<n;i++)a[i]=0
#define cfast std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pll pair<ll,ll>
#define inc(i,a,n) for(ll i=a;i<n;i++)
#define vset(a,n,m) for(ll i=0;i<n;i++)a[i]=m;
using namespace std;
ll types[20];
int vis[20000005];
int main() {
cfast;
ll n, m;
cin >> n >> m;
ll ans = 1;
ll cnt = 0;
inc(i, 1, 20) {
//cout << i << endl;
inc(j, 1, m+1) {
if (vis[i * j] == 0) {
cnt++;
vis[i * j] = 1;
}
}
types[i] = cnt;
}
inc(i, 1, n + 1)vis[i] = 0;
inc(i, 2, n + 1) {
if (vis[i] == 1)continue;
ll ct = 0,tmp=i;
while (tmp <= n) {
ct++;
vis[tmp] = 1;
tmp *= i;
}
ans += types[ct];
}
cout << ans << endl;
}