|
发表于 2024-12-7 12:18:40
|
显示全部楼层
回帖奖励 +5 鱼币
想起来之前做过的一个比较恶心的
CF1194G
哎, 退役了
- #include <bits/stdc++.h>
- using namespace std;
- /*
- 首先把 x / y
- 换成 k*dx / k*dy
- 枚举的是 x 和 y, 但是我们必须保证 k 相同, 并且 x, y 分别被 dx, dy 整除
- 于是乎我们状态中存下来 前 pos 位的 x, y 分别除以 dx, dy 的余数, 再存 x, y 中出现的数字
- 答案就是 余数都是 0 并且出现数字符合题意的状态的答案之和
- 举个栗子:
- 这个竖式的答案是 k, 我们按位枚举 k 的位数(这样保证了 k 相同), 现在 k 这一位是 i
- ______________
- dx ) A B j ...这里是 x 的位置, 在做除法, 枚举 x 的这一位为 j
- _________
- 上一次的余数 = rx
- 那么这次的余数就是 (rx*10 + j) - i*dx, 这个余数要在 [0, dx) 的范围
- 再用状压把这次出现的数位 j 打上去即可
- */
- const int N = 102;
- const int P = 998244353;
- // f(pos, sx, sy, rx, ry) 代表前 pos 位, x, y 带有的数字状态, x, y 除以 dx, dy 的余数
- int f[N][16][16][10][10];
- string s;
- int num[N], n;
- int dx, dy;
- int ans;
- // 分数值一样的一起算, 不然会算重
- // 情况最多的是 1/2 = 2/4 = 3/6 = 4/8 共 4 组
- // tot 是组数
- int choice[2][4], tot;
- // type == 0 表示是 x, type == 1 表示是 y
- int Add(int st, int d, int type){
- for(int i = 0; i < tot; i++){
- if(choice[type][i] == d){
- st |= (1 << i);
- return st;
- }
- }
- return st;
- }
- int dfs(int pos, int sx, int sy, int rx, int ry, bool lim){
- if(pos == n + 1){
- // 没有余数, 并且 x 中出现 dx, y 中出现了 dy
- if(!rx && !ry && (sx & sy)) return 1;
- return 0;
- }
- auto& cur = f[pos][sx][sy][rx][ry];
- if(!lim && ~cur) return cur;
- int res = 0;
- int up = 9;
- int newrx, newry;
- if(lim) up = num[pos];
- // 枚举 k 的数位(竖式答案), x / dx == y / dy == k
- for(int ki = 0; ki < 10; ki++){
- // 枚举 x 的数位(竖式被除数)
- for(int xi = 0; xi <= up; xi++){
- newrx = (rx*10 + xi) - ki*dx;
- if(newrx < 0) continue;
- if(newrx >= dx) break;
- // 枚举 y 的数位, 流程是一样的
- // y 比 x 小, 所以不用管
- for(int yi = 0; yi < 10; yi++){
- newry = (ry*10 + yi) - ki*dy;
- if(newry < 0) continue;
- if(newry >= dy) break;
- res = (res + dfs(pos + 1, Add(sx, xi, 0), Add(sy, yi, 1), newrx, newry, lim && (xi == up))) % P;
- }
- }
- }
- if(!lim) cur = res;
- return res;
- }
- int main(){
- ios::sync_with_stdio(0);
- cin.tie(0);
-
- cin >> s;
- n = s.size();
- for(int i = 1; i <= n; i++){
- num[i] = s[i - 1] - '0';
- }
- // dx == dy 的情况, 这时每个数都满足条件, ans += num
- for(int i = 1; i <= n; i++){
- ans = (ans*10 + num[i]) % P;
- }
- // 强制令 x > y (即 dx > dy), 这样只需要满足 x <= n 就行了
- for(int i = 1; i < 10; i++){
- for(int j = 1; j < i; j++){
- if(__gcd(i, j) != 1) continue;
- memset(f, -1, sizeof(f));
- for(tot = 0; tot < 4; tot++){
- if(i*(tot + 1) > 9) break;
- choice[0][tot] = i*(tot + 1);
- choice[1][tot] = j*(tot + 1);
- }
- dx = i, dy = j;
- long long w = (dfs(1, 0, 0, 0, 0, 1)*2ll) % P;
- ans = (ans + w) % P;
- }
- }
- cout << ans;
-
- return 0;
- }
复制代码 |
评分
-
查看全部评分
|