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;
}
上一篇:【A tour of go】练习题


下一篇:JS 中的定时器与延时器