abc 222 题解
E
一个背包一眼题。
先暴力算出每条边经过的次数,然后大力01背包,注意次数为 \(0\) 也要做背包。
这里我刚开始的做法时每次 \(dp[i]=dp[i+x]+dp[i-x]\),但这样还需要将数组扩大一倍,很麻烦,而且要起来。
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define uint unsigned int
#define LL long long
using namespace std;
const int MAXN = 10005, MAXM = 105, Mod = 998244353;
int n, m, k, a[MAXM], c[MAXN], d[MAXN], Fa[MAXN];
int dp[2][MAXN * MAXM * 2];
vector <int> v[MAXN];
void dfs(int x, int fa) {
Fa[x] = fa;
for(uint i = 0; i < v[x].size(); i ++) {
int y = v[x][i]; if(y == fa) continue;
d[y] = d[x] + 1; dfs(y, x);
}
}
int main() {
int x, y;
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= m; i ++) scanf("%d", &a[i]);
for(int i = 1; i < n; i ++) {
scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x);
}
dfs(1, -1);
for(int i = 1; i < m; i ++) {
x = a[i]; y = a[i + 1];
while(x != y) {
if(d[x] > d[y]) c[x] ++, x = Fa[x];
else c[y] ++, y = Fa[y];
}
}
// dp[i][j]=dp[i-1][j-ai]|dp[i-1][j+ai]
dp[1][n * m] = 1;
for(int i = 2; i <= n; i ++) {
for(int j = 0; j <= 2 * n * m; j ++) {
dp[i & 1][j] = 0;
if(j - c[i] >= 0) dp[i & 1][j] = (dp[i & 1][j] + dp[(i - 1) & 1][j - c[i]]) % Mod;
if(j + c[i] <= 2 * n * m) dp[i & 1][j] = (dp[i & 1][j] + dp[(i - 1) & 1][j + c[i]]) % Mod;
}
}
if(n * m + k < 0 || n * m + k > 2 * n * m) printf("0"); // 特判
else printf("%d", dp[n & 1][n * m + k]);
return 0;
}
其实换个角度,这里将一种颜色贡献看为 \(1\),一种看为 \(0\),简单计算一下会更好打。
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define uint unsigned int
#define LL long long
using namespace std;
const int MAXN = 10005, MAXM = 105, Mod = 998244353;
int n, m, k, a[MAXM], c[MAXN], d[MAXN], Fa[MAXN], all;
int dp[MAXN * MAXM * 2];
vector <int> v[MAXN];
void dfs(int x, int fa) {
Fa[x] = fa;
for(uint i = 0; i < v[x].size(); i ++) {
int y = v[x][i]; if(y == fa) continue;
d[y] = d[x] + 1; dfs(y, x);
}
}
int main() {
int x, y;
scanf("%d%d%d", &n, &m, &k); d[1] = 1;
for(int i = 1; i <= m; i ++) scanf("%d", &a[i]);
for(int i = 1; i < n; i ++) {
scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x);
}
dfs(1, -1);
for(int i = 1; i < m; i ++) {
x = a[i]; y = a[i + 1];
while(x != y) {
if(d[x] > d[y]) c[x] ++, x = Fa[x];
else c[y] ++, y = Fa[y];
}
}
for(int i = 1; i <= n; i ++) all += c[i];
dp[0] = 1;
for(int i = 2; i <= n; i ++) {
// 注意这里 c[i]=0时要进行操作
for(int j = all; j >= c[i]; j --) dp[j] = (dp[j] + dp[j - c[i]]) % Mod;
}
if(((all + k) & 1) || (all + k) / 2 < 0 || (all + k) / 2 > all) printf("0");
else printf("%d", dp[(all + k) / 2]);
return 0;
}
F
仙姑着。。。因为没调出来。。。
G
\(ax=0\pmod b<=>x=0\pmod {\frac {b} {\gcd(b,a)}}\)
\(\frac{x}{a}=0\pmod b<=>x=0\pmod {ab}\)
trick:\(a|b=>b=0\pmod a\)。
推一下式子:
\((10^k-1)*2/9=0\pmod x\)
\(10^k-1=0\ (\mathrm{mod}\ \frac {9x } {\gcd (9x,2)})\)。
\(10^k=1(...)\)
然后这里用欧拉定理即可,,
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <iostream>
#define LL long long
#define uint unsigned int
using namespace std;
int T, fuck, res = 0x3f3f3f3f;
int Gcd(int x, int y) { return y ? Gcd(y, x % y) : x; }
int Getphi(int x) {
int ans = x, t = sqrt(x);
for(int i = 2; i <= t; i ++) {
if(x % i == 0) ans = ans / i * (i - 1);
while(x % i == 0) x /= i;
}
if(x > 1) ans = ans / x * (x - 1); return ans;
}
int Qpow(int x, int y) {
int ans = 1;
for(; y; y >>= 1) {
if(y & 1) ans = (LL)ans * x % fuck;
x = (LL)x * x % fuck;
}
return ans;
}
int main() {
scanf("%d", &T);
while(T --) {
scanf("%d", &fuck); fuck = 9 * fuck;
if(fuck % 2 == 0) fuck >>= 1; res = 0x3f3f3f3f;
if(Gcd(fuck, 10) > 1) { printf("-1\n"); continue; }
int p = Getphi(fuck), g = sqrt(p);// printf("|%d|", p);
for(int i = 1; i <= g; i ++) {
if(p % i == 0) {
if(Qpow(10, i) == 1) res = min(res, i);
if(Qpow(10, p / i) == 1) res = min(res, p / i);
}
}
printf("%d\n", res);
}
return 0;
}