题意:n个人编号为[s+1, s+n],有n个座位编号为[1,n],编号为 i 的人只能坐到编号为它的约数的座位,问每个人是否都有位置坐。
题解:由于质数只能坐到1或者它本身的位置上,所以如果[n+1,n+s]区间内如果有多于一个质数时肯定无解,
有解时s 一定很小因为1e9以内,最远的两个素数相差282 (打表得出),
可以证明 [s+1,n]这一段数肯定坐到自己编号的位置上要更好
所以剩下的用匈牙利匹配一下即可
简单证明一下“ [s+1,n]这一段数肯定坐到自己编号的位置上要更好”
如果有更好的位置,设x为[s+1,n]内的一个数,y为大于n的一个数
且不存在比s小的数a 是得y%a=0
但是 x%a=0 且 y%x=0
这样显然矛盾
代码:
const int maxn = 1000; int n, s; vector<int> G[maxn]; bool vis[maxn]; int match[maxn]; bool dfs(int u) { for (int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if (vis[v]) continue; vis[v] = true; if (match[v] == -1 || dfs(match[v])) { match[v] = u; return true; } } return false; } int hungary(int n) //传入二分图一边的节点数 { int matches = 0; memset(match, -1, sizeof match); for(int i = 1; i <= n; ++i) { memset(vis, 0, sizeof vis); matches += dfs(i); } return matches; } void init() { for (int i = 1; i < maxn; i++) G[i].clear(); scanf("%d%d", &n, &s); } void solve() { if (s > 600 && n > 600) { printf("No "); return; } if (n <= 600) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if ((s + i) % j == 0) { G[i].push_back(j); } } } int m = hungary(n); if (m == n) printf("Yes "); else printf("No "); return; } for (int i = 1; i <= s; i++) { for (int j = 1; j <= s; j++) { if ((n + i) % j == 0) { G[i].push_back(j); } } } int m = hungary(s); if (m == s) printf("Yes "); else printf("No "); } int main() { int T, kase = 0; scanf("%d", &T); while (T--) { printf("Case #%d: ", ++kase); init(); solve(); } return 0; }