8.9 Round 1
今天是这几天考试中唯一一次发挥正常一点儿的...
T1:https://www.luogu.org/problem/T93119
这么小的数据,O(n^3)暴力就行
而我非常愚蠢加个二分,一样可以过
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<climits> #include<map> #include<queue> #include<cmath> using namespace std; #define O(x) cout << #x << " " << x << endl; #define B cout << "breakpoint" << endl; #define clr(a) memset(a,0,sizeof(a)); inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 305; int a1[maxn],a2[maxn]; int n,k; char s[maxn]; inline bool check(int d) { for(int i = 1;i + d - 1<= n;i++) for(int j = 1;j + d - 1 <= n;j++) { int cnt = 0; for(int t = 0;t < d;t++) if(a1[i + t] != a2[j + t]) cnt++; if(cnt <= k) return 1; } return 0; } int main() { freopen("master.in","r",stdin); freopen("master.out","w",stdout); n = read(),k = read(); scanf("%s",s); for(int i = 1;i <= n;i++) a1[i] = (int)s[i - 1] - 'a' + 1; scanf("%s",s); for(int i = 1;i <= n;i++) a2[i] = (int)s[i - 1] - 'a' + 1; int l = 0,r = n; while(l < r) { int mid = (l + r + 1) >> 1; if(check(mid)) l = mid; else r = mid - 1; } printf("%d",l); } /* 7 2 aabbaba bababbc */
T2:https://www.luogu.org/problem/T93120
考场上自信以为自己写的正解,没想到复杂度算错...
下次以为切题的时候,一定要好好算复杂度
70pts:f[u][s]:位于点u,还剩s条边可走
枚举起点s,容易处理环的情况
O(N^3)
正解:不考虑环,对于一条边u->v,它对答案的贡献是(d[u] - 1) *(d[v] - 1);
考虑去掉三元环,令s1为u能到达的点集,s2为v能到达的点集,这样对于s1与s2的并集,他们都可以成为三元环
于是统计并集中的点数,减去答案即可
用bitset记录点集,O(n^3 / 32)
bitset怎么用么...:https://www.cnblogs.com/zwfymqz/archive/2018/04/02/8696631.html
/*#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<climits> #include<map> #include<queue> #include<cmath> #pragma GCC optimize(3) #pragma GCC optimize("Ofast") using namespace std; #define O(x) cout << #x << " " << x << endl; #define B cout << "breakpoint" << endl; #define clr(a) memset(a,0,sizeof(a)); typedef long long ll; inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 1505; struct edge { int to,next; }e[maxn * maxn]; int fir[maxn],alloc; void adde(int u,int v) { e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v; swap(u,v); } int s; ll f[maxn][4];//f[u][step] : 在u,剩step条边可走的方案 ll dfs(int u,int pre,int step)//在u,前一个点为pre,剩step条边可走 的方案数 { if(f[u][step]) return f[u][step]; if(step == 0) return 1ll; for(int i = fir[u];i;i = e[i].next) { int v = e[i].to; if(v == s) continue; f[u][step] += dfs(v,u,step - 1); } if(step == 1) f[u][step]--; return f[u][step]; } int main() { freopen("tour.in","r",stdin); freopen("tour.out","w",stdout); int n = read(); for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) { int x; scanf("%1d",&x); if(x) adde(i,j); } ll ans = 0; for(int i = 1;i <= n;i++) { clr(f); s = i; ans += dfs(s,0,3); } printf("%lld",ans); }*/ /* 4 0101 1010 0101 1010 */ #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<climits> #include<map> #include<queue> #include<cmath> #include<bitset> #pragma GCC optimize(3) #pragma GCC optimize("Ofast") using namespace std; #define O(x) cout << #x << " " << x << endl; #define B cout << "breakpoint" << endl; #define clr(a) memset(a,0,sizeof(a)); typedef long long ll; inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } typedef long long ll; const int maxn = 1505; int d[maxn]; bitset<1505> in[maxn]; int main() { freopen("tour.in","r",stdin); freopen("tour.out","w",stdout); int n = read(); for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) { int x; scanf("%1d",&x); if(x) d[i]++,in[i][j] = 1; } ll ans = 0; for(int i = 1;i <= n;i++) for(int j = 1;j < i;j++) { if(!in[i][j]) continue; ll x = 1ll * (in[i] & in[j]).count(); ans += (d[i] - 1) * (d[j] - 1) - x; } printf("%lld",ans << 1); }
T3:https://www.luogu.org/problem/T93121
考场上Trie树乱搞,至今不知道为什么是错的...
正解是优化建边
对于每一个i,把val[i]拆出来,i->val[i]连一条边权为1的边,然后val[i]向val[i]去掉一个1的权点连边,边权为0
先bfs,对于队首u,先走u的边权为1的边,再dfs边权为0的边
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<climits> #include<map> #include<queue> #include<cmath> using namespace std; #define O(x) cout << #x << " " << x << endl; #define B cout << "breakpoint" << endl; #define clr(a) memset(a,0,sizeof(a)); #define pii pair<int,int> #define mp make_pair #define fi first #define se second inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 2e6 + 5; struct edge { int to,next,cost; }e[maxn << 1]; int fir1[maxn],alloc,fir2[maxn]; void adde(int u,int v,int op) { if(op == 1) e[++alloc].next = fir1[u], fir1[u] = alloc, e[alloc].to = v; else e[++alloc].next = fir2[u],fir2[u] = alloc,e[alloc].to = v; } const int M = 1 << 20; int dis[maxn]; queue<int> q; int n,m; void dfs(int u,int d) { if(dis[u] >= 0) return; dis[u] = d; q.push(u); for(int i = fir2[u];i;i = e[i].next) dfs(e[i].to,d); if(u > M) return; for(int i = 0;i < 20;i++) if(u >> i & 1) dfs(u ^ (1 << i),d); } void bfs() { memset(dis,-1,sizeof(dis)); dis[M + 1] = 0; q.push(M + 1); dfs(M + 1,0); while(q.size()) { int u = q.front(); q.pop(); for(int i = fir1[u];i;i = e[i].next) dfs(e[i].to,dis[u] + 1); } for(int i = 1;i <= n;i++) printf("%d\n",dis[M + i]); } int main() { freopen("walk.in","r",stdin); freopen("walk.out","w",stdout); n = read(),m = read(); for(int i = 1;i <= n;i++) { int x = read(); adde(M + i,x,1); adde(x,M + i,2); } for(int i = 1;i <= m;i++) { int u = read(),v = read(); adde(u + M,v + M,1); } bfs(); }