UVALive 6198 A Terribly Grimm Problem
题目大意是
给出L,H 10^10范围
为[L, H]这个连续的整数区间寻找一个序列。
序列的长度要跟[L, H]一样
然后序列中的数都是素数,并且互不相同
并且序列中第i个数 要求是L + i -1的一个素因子
最后要求序列的字典序最小
然后可以看到L,H很大
但是我们需要注意的是,这个序列长度肯定不会很大
太大了肯定满足不了题目的要求。
所以这个整数区间的数我们可以一个一个的,先把每个数都素因子分解了,放起来。
然后就发现。 这不就是二分图匹配么。
但是题目求的是字典序最小。
所以我们就对每个数。
对其所有的素因子,尝试改变匹配,然后寻找增广路。
如果能找到。就固定这条边
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <string> #include <cmath> #include <vector> #include <map> #include <set> #include <algorithm> #define MAXN 111111 #define N 505 using namespace std; bool tag[MAXN]; int p[MAXN]; int cnt; int mark[5555], used[5555]; int cx[N], cy[5555]; vector<int>g[N]; int ans[N]; int m, up; long long l, r; long long a[MAXN]; set<long long>s; map<long long, int> id; void getprime() { cnt = 0; tag[1] = 1; for(int i = 2; i < 100000; i++) { if(!tag[i]) p[cnt++] = i; for(int j = 0; j < cnt && p[j] * i < 100000; j++) { tag[i * p[j]] = 1; if(i % p[j] == 0) break; } } } void get(long long x) { for(int i = 0; i < cnt && x >= (long long)p[i] * (long long)p[i]; i++) if(x % p[i] == 0) { s.insert(p[i]); while(x % p[i] == 0) x /= p[i]; } if(x != 1) s.insert(x); } void get2(long long x) { long long tx = x; for(int i = 0; i < cnt && x >= (long long)p[i] * (long long)p[i]; i++) if(x % p[i] == 0) { long long tmp = (long long)p[i]; while(x % tmp == 0) x /= tmp; g[tx - l + 1].push_back(id[tmp]); } if(x != 1) g[tx - l + 1].push_back(id[x]); } int path(int u) { int sz = g[u].size(); for(int i = 0; i < sz; i++) { int v = g[u][i]; if(!mark[v] && !used[v]) { mark[v] = 1; if(cy[v] == -1 || path(cy[v])) { cx[u] = v; cy[v] = u; return 1; } } } return 0; } bool ok(int t) { memset(cy, -1, sizeof(cy)); for(int i = t + 1; i <= up; i++) { memset(mark, 0, sizeof(mark)); if(!path(i)) return false; } return true; } void fix() { for(int i = 1; i <= up; i++) { int sz = g[i].size(); for(int j = 0; j < sz; j++) { int v = g[i][j]; if(used[v]) continue; cx[i] = v; used[v] = 1; if(!ok(i)) used[v] = 0; else break; } used[cx[i]] = 1; } } void out(long long a ) { if(a >= 10) out(a / 10); putchar('0' + a % 10); } int main() { getprime(); while(scanf("%lld%lld", &l, &r) != EOF) { if(l == 0 && r == 0) break; s.clear(); id.clear(); up = r - l + 1; for(int i = 1; i <= up; i++) g[i].clear(); memset(ans, -1, sizeof(ans)); memset(used, 0, sizeof(used)); m = 0; for(long long i = l; i <= r; i++) get(i); for(set<long long>::iterator it = s.begin(); it != s.end(); it++) { a[m++] = *it; id[a[m - 1]] = m; } for(long long i = l; i <= r; i++) get2(i); fix(); for(int i = 1; i < up; i++) { //printf("%lld ", a[cx[i] - 1]); out(a[cx[i] - 1]); putchar(' '); } out(a[cx[up] - 1]); putchar('\n'); //printf("%lld\n", a[cx[up] - 1]); } return 0; }