给你一个正整数
求满足下列条件的正整数三元组
4
5
满足条件的三元组有
100
323
100000000000
5745290566750
枚举
控制枚举量:
int main() {
long long ans = 0;
long long n; cin >> n;
long long cnt = 0;
for (long long a = 1; a * a * a <= n; a++)
for (long long b = a; a * b * b <= n; b++) {
ans += n / a / b - b + 1;
}
cout << ans << '\n';
}
cbrt()。用最大的数据
最直接的办法:运行程序算枚举次数。
我们把满足下列条件的正整数
例如
求不小于
152
159
88
88
8989898989
9876543210
不小于
设
解空间:长度
等差数列由首项和公差确定。
枚举量小于
int main() {
long long x;
cin >> x;
int len = to_string(x).size();
long long ans = x * 10;
for (int a = 1; a <= 9; a++) {
for (int d = -9; d <= 9; d++) {
long long sum = 0;
for (int i = 0; i < len; i++) {
int t = a + d * i;
if (t < 0 || t > 9) break;
sum = sum * 10 + t;
}
if (sum >= x) {
ans = min(sum, ans);
}
}
}
cout << ans << '\n';
}
给你两个正整数
找到满足下列两条件的最小正整数
我们要找两个数
int main() {
long long N, M;
cin >> N >> M;
long long ans = -1;
for (long long a = 1; a <= N; a++) {
long long b = (M + (a - 1)) / a;
if (b <= N) {
if (ans == -1 || ans > a * b)
ans = a * b;
}
if (a * a >= M)
break;
}
cout << ans;
return 0;
}
给定正整数
输出两个数
枚举因数类问题的一个常用技巧:
在《校庆》这道题中,我们要枚举
void solve(long long n) {
int C = 1;
long long B = n;
for (long long b = 2; b * b * b <= n; b++) {
if (n % (b * b) == 0) {
long long t = n / (b * b);
int cnt = 2;
while (t % b == 0) {
t /= b;
cnt++;
}
if (cnt >= C) {
C = cnt;
B = b;
}
}
}
if (C <= 2) // 当 b > n**{1/3} 时,n 在 b 进制下末尾最多有 2 个 0
for (int k = 1; k * k * k < n; k++)
if (n % k == 0) {
long long t = sqrt(n / k);
if (t * t == n / k) {
C = 2;
B = t;
break;
}
}
cout << B << ' ' << C << '\n';
}
对于整数
给定整数
对于
给你一个正整数
分解因式
注意到
所以
我们得到
设
然后怎么办?
以
即
解此二次方程就得到
其实解这个方程也不是很容易。
我们有
两式相减,得
那么
开平方根就得到
有了
void solve(long long N) {
for (long long d = 1; d * d * d < N; d++) {
if (N % d) continue;
long long k = N / d - d * d;
if (k % 3) continue;
long long xy = k / 3;
long long t = d * d + 4 * xy;
long long s = sqrt(t);
if (s * s != t) continue;
// x + y = s; x - y = d
long long x = (s + d) / 2;
long long y = s - x;
cout << x << ' ' << y << '\n'; return;
}
cout << -1 << '\n';
}

有
第
你可以从
int main() {
int n, m; cin >> n >> m;
vector<int> X[3];
for (int i = 0; i < n; i++) {
int t, x; cin >> t >> x;
X[t].push_back(x);
}
for (int i = 0; i < 3; i++)
sort(X[i].rbegin(), X[i].rend());
vector<long long> sum[3]; // 前缀和
for (int i = 0; i < 3; i++) {
sum[i].resize(X[i].size() + 1);
for (int j = 0; j < X[i].size(); j++)
sum[i][j + 1] = sum[i][j] + X[i][j];
}
long long ans = 0;
int j = 0; // 需要的开罐器的数量
for (int i = 0; i <= (int) X[1].size(); i++) {
if (i > m) break;
if (sum[2][j] < i) j++;
if (j > (int) X[2].size() || i + j > m) break;
int k = min(m - i - j, (int) X[0].size()); // 拿的易拉罐的数量
ans = max(ans, sum[0][k] + sum[1][i]);
}
cout << ans << '\n';
}
有时候一个变量确定了,其他变量都确定了。
给你一个
有
坐标平面上有一些村庄。我们可以把一个村庄当成一个点。
我们要挖护城河来保护这些村庄。
给你一个
可以把护城河看成平面上的一个多边形。这个多边形要满足下列条件。
求挖护城河有多少种方式。
1 0 0 0
0 0 1 0
0 0 0 0
1 0 0 0
1272
下列两种护城河满足条件。

下列四种护城河不满足条件。

如何判断是否有洞?
int a[4][4];
int vis[4][4];
int main() {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
cin >> a[i][j];
int ans = 0;
for (int s = 1; s < 1 << 16; s++) {
memset(vis, 0, sizeof vis);
for (int i = 0; i < 16; i++) {
if (s >> i & 1) {
vis[i / 4][i % 4] = 1; //给选中的格子打标记
}
}
ans += check();
}
cout << ans << '\n';
}
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
void dfs(int r, int c, int type) { // 搜连通块
vis[r][c]++;
for (int i = 0; i < 4; i++) {
int x = r + dir[i][0], y = c + dir[i][1];
if (0 <= x && x < 4 && 0 <= y && y < 4 && vis[x][y] == type)
dfs(x, y, type);
}
}
int check() { // 检查
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
if (a[i][j] == 1 && vis[i][j] == 0) //没有选择全部村庄
return 0;
int sx, sy;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
if (vis[i][j]) {
sx = i;
sy = j;
}
dfs(sx, sy, 1);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
if (vis[i][j] == 1)
return 0;// 选中的格子不连通
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
if (vis[i][j] == 0 && (i == 0 || j == 0 || i == 3 || j == 3))
dfs(i, j, 0);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
if (vis[i][j] == 0) // 选中的格子有洞
return 0;
return 1;
}
自顶向下、逐步求精的模块化程序设计。
给定有
求
保证存在满足条件的四个点。
此思路也可说是 meet in the middle。
const int maxn = 2500 + 5;
int n, m, k;
vector<int> g[maxn];
long long p[maxn]; //景点的分数
vector<int> cand[maxn];
int dist[maxn][maxn];
const int INF = 1e9;
void bfs(int s) {
for (int i = 1; i <= n; i++)
dist[s][i] = INF;
queue<int> q;
q.push(s);
dist[s][s] = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v : g[u])
if (dist[s][v] == INF) {
dist[s][v] = dist[s][u] + 1;
q.push(v);
}
}
}
bool cmp(int i, int j) {
return p[i] > p[j];
}
int main() {
cin >> n >> m >> k;
for (int i = 2; i <= n; i++) cin >> p[i];
for (int i = 0; i < m; i++) {
int u, v; cin >> u >> v;
g[u].push_back(v); g[v].push_back(u);
}
for (int i = 1; i <= n; i++) bfs(i);
vector<int> ad;
for (int i = 2; i <= n; i++)
if (dist[1][i] <= k + 1) ad.push_back(i);
sort(ad.begin(), ad.end(), cmp);
for (int i = 2; i <= n; i++)
for (int v : ad)
if (v != i && dist[i][v] <= k + 1) {
cand[i].push_back(v);
if (cand[i].size() == 3) break;
}
long long ans = 0;
for (int b = 2; b <= n; b++)
for (int c = b + 1; c <= n; c++)
if (dist[b][c] <= k + 1)
for (int a : cand[b])
for (int d : cand[c])
if (a != c && a != d && b != d)
ans = max(ans, p[a] + p[b] + p[c] + p[d]);
cout << ans << '\n';
}
有一个简单无向图
编号为
一个长度为
若图

1 7 2 9
一个二分图,左边有





时间:
鸽笼原理
vector<int> a[300005];
int vis[3005][3005];
int main() {
int S, T, M;
cin >> S >> T >> M;
while (M--) {
int u, v;
cin >> u >> v;
a[u].push_back(v - S);
}
for (int u = 1; u <= S; u++) {
for (int i = 0; i < a[u].size(); i++)
for (int j = 0; j < i; j++) {
int x = min(a[u][i], a[u][j]);
int y = max(a[u][i], a[u][j]);
if (vis[x][y] == 0) {
vis[x][y] = u;
} else {
cout << vis[x][y] << ' ' << u << ' ' << x + S << ' ' << y + S;
return 0;
}
}
}
cout << -1;
}
许多问题不是需要用什么算法才能解决的,好好枚举就足够了。