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

题目大意:

CF 401D Roman and Numbers
题目大意:给一个数(<=1e18),求它的打乱数字顺序后可以整除m的数字数量(自己本身也算,不能有首零)。

解:

取模数位的板子题,由同余定理可以推出一个数位上10再取模等价于在他左移一位的取模,本题最多只有18位,所以可以状压解决全排列问题,复杂度O(2^1810),注意判断首零情况.
值得一提的是由于全排列中相同的数字互相交换得到的数字是相同的,所以最后要除以各种相同情况,由于对于每一种情况重复率是相同的,所以结果直接除就行。
水。

代码

代码
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
56
57
58
59
60

#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 1000000007
#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 dp[300000][100],digits[19],cnt[10],f[20];
int main() {
cfast;
ll n, m;
cin >> n >> m;
ll wei = 0;
while (n) {
digits[wei++] = n % 10;
cnt[digits[wei - 1]]++;
n /= 10;
}
ll fac = 1;
f[1] = 1;
inc(i, 2, 19) {
f[i] = f[i - 1] * i;
}
inc(i, 0, 10) {
if (cnt[i] > 1)fac *= f[cnt[i]];
}
for(ll st = 0; st < (1 << wei); st++) {
inc(i, 0, wei) {
if (st == 0) {
if (digits[i] != 0) {
dp[1 << i][digits[i] % m] = 1;
}
}
else {
if ((st & (1 << i)) != 0)continue;
inc(k, 0, m) {
dp[st + (1 << i)][(k * 10 + digits[i]) % m] += dp[st][k];
}
}
}
}
cout << dp[(1 << wei) - 1][0]/fac;
}