NOIP多校联考9
A.理想路径
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2003; const ll mod = 20040820; const int INF = 2147483647; const int lim = 1e4 + 1; int n, m, q, dfn[maxn<<1], tot; bool a[maxn][maxn], flag, vis[maxn], tag; vector<int> son[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } void dfs(int x, int y) { if(vis[x]) { flag = 1; return; } if(!flag && !tag) dfn[++tot] = x; if(x == y) { tag = 1; return; } vis[x] = 1; for(int i=0; i<son[x].size(); i++) { int v = son[x][i]; dfs(v, y); if(flag || tag) return; } if(!flag && !tag) dfn[++tot] = x; } int main() { //freopen("tiao.txt", "r", stdin); n = read(); m = read(); q = read(); for(int i=1; i<=m; i++) { int x = read(), y = read(); a[x][y] = 1; son[x].push_back(y); } for(int i=1; i<=n; i++) { sort(son[i].begin(), son[i].end()); } for(int k=1; k<=n; k++) { for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if(a[i][k] && a[k][j]) { a[i][j] = 1; } } } } /*printf("\n\n"); for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { printf("%d ", a[i][j]); } printf("\n"); } printf("\n\n");*/ while(q--) { int x = read(), y = read(), k = read(); if(x == y) { if(k == 1) { printf("%d\n", x); continue; } else { printf("-1\n"); continue; } } if(!a[x][y]) { printf("-1\n"); continue; } flag = 0; tag = 0; tot = 0; memset(vis, 0, sizeof(vis)); memset(dfn, 0, sizeof(dfn)); dfs(x, y); if(tot < k || flag) { printf("-1\n"); continue; } else { /*printf("x = %d y = %d\n", x, y); for(int i=1; i<=tot; i++) { printf("%d ", dfn[i]); } printf("\n\n");*/ printf("%d\n", dfn[k]); } } return 0; }
每个问题跑一遍dfs,sort vector的灵感好像和[NOIP2018]旅行类似?
---插入:旅行:n=m的情况一定有一条环上的边不走,所以可以暴力枚举删掉哪条边,这个操作的dfs不错哦,至于怎么判断字典序的大小,直接在数组里暴力判断就好了(hash什么的想多了)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 5e3 + 2; const ll mod = 998244353; const int INF = 2147483647; const int lim = 1e4 + 1; int n, m, ans[maxn], res[maxn], u1[maxn<<1], v1[maxn<<1], cnt; int du, dv, tot, cir[maxn]; bool flag, vis[maxn]; vector<int> a[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct Edge { int from, to; }e[5010]; //找出环,把环上的变压进数组里 void dfs3(int x, int fa) { vis[x] = 1; for(int i=0; i<a[x].size(); i++) { int to = a[x][i]; if(to == fa) continue; if(vis[to]) { flag = 1; cir[to] = 1; cir[x] = 1; u1[++cnt] = x; v1[cnt] = to; return; } dfs3(to, x); if(flag && cir[to]) { if(cir[x]) { flag = 0; u1[++cnt] = x; v1[cnt] = to; return; } else { cir[x] = 1; u1[++cnt] = x; v1[cnt] = to; return; } } } } void dfs1(int u, int fa) { if(vis[u]) return; vis[u] = 1; res[++tot] = u; for(int i=0; i<a[u].size(); i++) { int v = a[u][i]; if(v == fa) continue; if((u==du&&v==dv)||(u==dv&&v==du)) continue; dfs1(v, u); } } int check() { for(int i=1; i<+n; i++) { if(res[i] < ans[i]) return 1; else if(res[i] > ans[i]) return 0; } return 0; } void update() { for(int i=1; i<=n; i++) { ans[i] = res[i]; } } void dfs2(int u, int fa) { ans[++tot] = u; for(int i=0; i<a[u].size(); i++) { int v = a[u][i]; if(v == fa) continue; dfs2(v, u); } } int main() { n = read(); m = read(); for(int i=1; i<=m; i++) { int x = read(), y = read(); a[x].push_back(y); a[y].push_back(x); e[i].from = x; e[i].to = y; } for(int i=1; i<=n; i++) { sort(a[i].begin(), a[i].end()); } if(m == n) { dfs3(1, 0); flag = 1; for(int i=1; i<=cnt; i++) { du = u1[i]; dv = v1[i]; memset(vis, 0, sizeof(vis)); tot = 0; dfs1(1, 0); if(tot < n) continue; if(flag) { update(); flag = 0; } if(check()) { update(); } } for(int i=1; i<=n; i++) { printf("%d ", ans[i]); } } else { dfs2(1, 0); for(int i=1; i<=n; i++) { printf("%d ", ans[i]); } } return 0; }
--come back:我不知道这题怎么离线啊……(⊙o⊙)…
B.第一题
相乘等于完全平方数?n*m暴力枚举……
(同学的经验,提交的代码中如果出现了srand(time(0))会因为运行错误爆0,尽管你可能并没有应用随机数……)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 3; const ll mod = 20040820; const int INF = 2147483647; const int lim = 1e4 + 1; int n, m, cnt[maxn], p; ll ans; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { //freopen("one.in", "r", stdin); n = read(); m = read(); if(n > m) swap(n, m); p = sqrt(m); for(int i=1; i<=p; i++) { cnt[i*i] = 1; } for(int i=2; i<=m; i++) { cnt[i] += cnt[i-1]; } ans = n-cnt[n]; ans += cnt[n] * cnt[m]; printf("%lld\n", ans); return 0; }
这叫什么?按照100的正解改却T了个30!?据说按照n方暴力加个大样例的特判都能水个30……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 3; const ll mod = 20040820; const int INF = 2147483647; const int lim = 1e4 + 1; int v[maxn], prime[maxn], n, m, cnt[maxn], ans, hav[maxn], num, tot; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } void primes(int n) { for(int i=2; i<=n; i++) { if(v[i] == 0) { v[i] = i; prime[++tot] = i; } for(int j=1; j<=tot; j++) { if(prime[j]>v[i] || prime[j]*i > n) break; v[i*prime[j]] = prime[j]; } } } int main() { n = read(); m = read(); if(n > m) swap(n, m); primes(n); for(int i=1; i<=n; i++) { memset(cnt, 0, sizeof(cnt)); memset(hav, 0, sizeof(hav)); int f = i; num = 0; while(f && v[f]) { cnt[v[f]]++; if(hav[num] != v[f]) hav[++num] = v[f]; f /= v[f]; } int t = 1; for(int j=1; j<=num; j++) { if(cnt[hav[j]] & 1) { t *= hav[j]; } } int g = m/t; ans += sqrt(g); } printf("%d\n", ans); return 0; }
统计个数和统计乘积可以是一步操作啊!两个memset和为了判断新的来个循环不T才怪
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 3; const ll mod = 20040820; const int INF = 2147483647; const int lim = 1e4 + 1; int v[maxn], prime[maxn], n, m, ans, num, tot; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } void primes(int n) { for(int i=2; i<=n; i++) { if(v[i] == 0) { v[i] = i; prime[++tot] = i; } for(int j=1; j<=tot; j++) { if(prime[j]>v[i] || prime[j]*i > n) break; v[i*prime[j]] = prime[j]; } } } int main() { n = read(); m = read(); if(n > m) swap(n, m); primes(n); for(int i=1; i<=n; i++) { int f = i, t = 1; num = 0; while(f && v[f]) { int cnt = 0, zs = v[f]; while(f && (f%zs==0)) cnt++, f/=zs; if(cnt&1) t *= zs; } int g = m/t; ans += sqrt(g); } printf("%d\n", ans); return 0; }
C.消除贫困
我居然AC了?!由于过程不重要,离线处理一下问题(一开始我还想用线段树来着……)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5 + 3; const ll mod = 20040820; const int INF = 2147483647; const int lim = 1e4 + 1; int n, a[maxn], v[maxn], Max2, qes; struct node { int f, x, y; }q[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { //freopen("welloff.in", "r", stdin); //freopen("tiao.txt", "w", stdout); n = read(); for(int i=1; i<=n; i++) { a[i] = read(); } qes = read(); for(int i=1; i<=qes; i++) { q[i].f = read(); if(q[i].f == 1) { q[i].x = read(); q[i].y = read(); } else { q[i].x = read(); } } for(int i=qes; i>=1; i--) { if(q[i].f == 1) { if(!v[q[i].x] && q[i].y>Max2) { v[q[i].x] = q[i].y; //printf("v[%d] = %d\n", q[i].x, v[q[i].x]); } else if(!v[q[i].x] && q[i].y<=Max2) { v[q[i].x] = Max2; //printf("v[%d] = %d\n", q[i].x, v[q[i].x]); } } else { Max2 = max(Max2, q[i].x); //printf("Max2 = %d\n", Max2); } } for(int i=1; i<=n; i++) { if(v[i]) { printf("%d ", v[i]); } else { printf("%d ", max(a[i], Max2)); } } printf("\n"); return 0; }
D.数串
只会n=1和m=0的magic dfs... 可以重复的dfs想了好久,高精度加法调了半天最后发现n<=6的数据范围完全没必要,用得着的数据范围dfs会被T飞……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 605; const ll mod = 20040820; const int INF = 2147483647; const int lim = 1e4 + 1; int n, m, k, b[maxn], c[maxn], ans[maxn], num; bool v[maxn][maxn]; struct node { int a, b; }p[107]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } void add(int a[], int b[], int c[]) { num = max(n, num); int x = 0; for(int i=1; i<=num; i++) { c[i] = a[i] + b[i] + x; x = 0; x = c[i]/10; c[i] %= 10; } if(x) c[++num] = x; } void dfs(int a, int n) { if(a > n) { add(b, c, ans); for(int i=1; i<=num; i++) { c[i] = ans[i]; ans[i] = 0; } return; } for(int i=1; i<=k; i++) { if(v[a][i]) continue; v[a][i] = 1; b[a] = i; dfs(a+1, n); v[a][i] = 0; } } int main() { n = read(); m = read(); k = read(); for(int i=1; i<=m; i++) { p[i].a = read(); p[i].b = read(); } if(n == 1) { printf("%d\n", k); int an = (1+k)*k/2; printf("%d\n", an); exit(0); } if(m == 0) { ll an = 1; for(int i=1; i<=n; i++) { an *= k; } printf("%lld\n", an); dfs(1, n); reverse(c+1, c+1+num); for(int i=1; i<=num; i++) { printf("%d", c[i]); } exit(0); } return 0; }
正解之不加滚动数组也不加高精度所以WA 40
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 503; const ll mod = 20040820; const int INF = 2147483647; const int lim = 1e4 + 1; int n, m, k, nt[maxn][maxn], g[maxn][maxn]; bool can[520][maxn]; int cnt[maxn][520], sum[maxn][520]; ll an1, an2; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } inline int lowbit(int x) { return x & -x; } int main() { n = read(); m = read(); k = read(); for(int i=1; i<=m; i++) { int x = read(), y = read(); nt[x][y] = 1; } for(int i=1; i<=k; i++) { for(int j=1; j<=k; j++) { if(nt[i][j]) { g[i][++g[i][0]] = j; } } } int Max = (1<<k)-1; for(int i=0; i<=Max; i++) { for(int j=1; j<=k; j++) { can[i][j] = 1; } } for(int j=0; j<=Max; j++) { int plk = j; while(plk) { int now = lowbit(plk); plk -= now; int yy = 0; while(now>>yy) yy++; for(int p=1; p<=g[yy][0]; p++) { can[j][g[yy][p]] = 0; } } } for(int i=0; i<k; i++) { cnt[1][(1<<i)] = 1; sum[1][(1<<i)] = i+1; } for(int i=1; i<=n; i++) { for(int j=0; j<=Max; j++) { for(int p=1; p<=k; p++) { if(can[j][p]) { cnt[i+1][j|(1<<(p-1))] += cnt[i][j]; sum[i+1][j|(1<<(p-1))] += 10*sum[i][j]+cnt[i][j]*p; } } } } for(int j=0; j<=Max; j++) { an1 += cnt[n][j]; an2 += sum[n][j]; } printf("%lld\n%lld\n", an1, an2); return 0; }
然后我加上了高精度和滚动数组TLE 70……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 503; const ll mod = 20040820; const int INF = 2147483647; const int lim = 1e4 + 1; int n, m, k, nt[maxn][maxn], g[maxn][maxn]; bool can[520][maxn]; //int cnt[maxn][520], sum[maxn][520]; //ll an1, an2; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct node { int p[607], len; node() { memset(p, 0, sizeof(p)); len = 0; } }; node cnt[2][520], sum[2][520], an1, an2; node operator + (const node &a, const node &b) { node c; c.len = max(a.len, b.len); int x = 0; for(int i=1; i<=c.len; i++) { c.p[i] = a.p[i] + b.p[i] + x; x = c.p[i] / 10; c.p[i] %= 10; } if(x > 0) c.p[++c.len] = x; return c; } node operator * (const node &a, const int &b) { node c; c.len = a.len; int x = 0; for(int i=1; i<=c.len; i++) { c.p[i] = a.p[i] * b + x; x = c.p[i] / 10; c.p[i] %= 10; } while(x > 0) { c.p[++c.len] = x % 10; x /= 10; } return c; } inline int lowbit(int x) { return x & -x; } int main() { n = read(); m = read(); k = read(); for(int i=1; i<=m; i++) { int x = read(), y = read(); nt[x][y] = 1; } for(int i=1; i<=k; i++) { for(int j=1; j<=k; j++) { if(nt[i][j]) { g[i][++g[i][0]] = j; } } } int Max = (1<<k)-1; for(int i=0; i<=Max; i++) { for(int j=1; j<=k; j++) { can[i][j] = 1; } } for(int j=0; j<=Max; j++) { int plk = j; while(plk) { int now = lowbit(plk); plk -= now; int yy = 0; while(now>>yy) yy++; for(int p=1; p<=g[yy][0]; p++) { can[j][g[yy][p]] = 0; } } } int w = 1; /*for(int i=0; i<k; i++) { cnt[w][(1<<i)] = 1; sum[w][(1<<i)] = i+1; }*/ for(int i=0; i<k; i++) { cnt[w][(1<<i)].len = 1; cnt[w][(1<<i)].p[1] = 1; sum[w][(1<<i)].len = 1; sum[w][(1<<i)].p[1] = i+1; } for(int i=1; i<=n; i++) { w ^= 1; for(int j=0; j<=Max; j++) { cnt[w][j].len = 0; memset(cnt[w][j].p, 0, sizeof(cnt[w][j].p)); sum[w][j].len = 0; memset(sum[w][j].p, 0, sizeof(sum[w][j].p)); } for(int j=0; j<=Max; j++) { for(int p=1; p<=k; p++) { if(can[j][p]) { cnt[w][j|(1<<(p-1))] = cnt[w^1][j]+cnt[w][j|(1<<(p-1))]; sum[w][j|(1<<(p-1))] = sum[w^1][j]*10+cnt[w^1][j]*p+sum[w][j|(1<<(p-1))] ; } } } } for(int j=0; j<=Max; j++) { an1 = cnt[w^1][j]+an1; an2 = sum[w^1][j]+an2; } //printf("%lld\n%lld\n", an1, an2); for(int i=an1.len; i>0; i--) { printf("%d", an1.p[i]); } printf("\n"); for(int i=an2.len; i>0; i--) { printf("%d", an2.p[i]); } return 0; }
关于我加了一个m=0的特判它反而变成了TLE 40这件事……难道特判不是这么写的?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
if(m == 0) { node tat, kat; int sss = k*(k+1)/2, sf = sss; while(sss) { tat.len++; tat.p[tat.len] = sss%10; sss /= 10; } kat.len = 1; kat.p[1] = k; for(int i=1; i<n; i++) { tat = tat*10*k; kat = kat*sf; tat = tat + kat; } for(int i=kat.len; i>0; i--) { printf("%d", kat.p[i]); } printf("\n"); for(int i=tat.len; i>0; i--) { printf("%d", tat.p[i]); } exit(0); }
时光花火,水月星辰