ICPC 2019-2020 North-Western Russia Regional Contest 补题部分
已做A、M,E和H思路已經有了沒調AC
已補BEJH
最終已完成ABEJHM
B - Bad Treap
大佬題解
感覺這題就很玄學。。。
E - Equidistant
隊友想的方法:先以1為根節點跑一邊dfs,記錄每個節點的深度,然后把m個關鍵點中,深度最大的點mx和深度最小的點mn拿出來,找到這兩個點路徑上的中點s(depmx?deps=deps?deplca+depmn?deplcadep_{mx}-deps=dep_s-dep_{lca}+dep_{mn}-dep_{lca}depmx??deps=deps??deplca?+depmn??deplca?),找到該點后,以該點為根節點重建樹,那么m個關鍵的的深度一定相等才滿足題意。
感覺上述方法沒有錯但是一直wa14,最后我把以1為根節點跑dfs改成以任意一個關鍵點先跑一邊dfs,那么深度最小的點就是根節點,上述式子都不變就AC了,很奇怪
最終隊友舉了個反例找到了以1為根跑dfs為什么會出問題。我hack我自己hhh
8 3 1 2 2 3 3 7 3 4 4 5 4 6 7 8 5 6 8 #define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #pragma GCC optimize(2) #include<set> #include<map> #include<cmath> #include<queue> #include<random> #include<bitset> #include<string> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<unordered_map> #include<unordered_set> using namespace std; typedef long long ll; typedef pair<int,int> pii; const int N=200010; int h[N],e[2*N],ne[2*N],idx; int n,m,c[N]; bool st[N]; int fa[N],dep[N]; void add(int a,int b) {e[idx]=b;ne[idx]=h[a];h[a]=idx++; } void dfs(int u,int p) {fa[u]=p;dep[u]=dep[p]+1;for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(j==p) continue;dfs(j,u);} } int lca(int a,int b) {while(a) {st[a]=1;a=fa[a];}while(b){if(st[b]) return b;b=fa[b];} } int main() {IO;int T=1;//cin>>T;while(T--){memset(h,-1,sizeof h);cin>>n>>m;for(int i=1;i<n;i++){int a,b;cin>>a>>b;add(a,b),add(b,a);}for(int i=1;i<=m;i++) cin>>c[i];dfs(c[1],0);//以任意一個關鍵跑dfs//dfs(1,0); 以1為根節點跑dfsint mx=-1,mn=-1;for(int i=1;i<=m;i++){if(mx==-1||dep[mx]<dep[c[i]]) mx=c[i];//最大深度點的編號if(mn==-1||dep[mn]>dep[c[i]]) mn=c[i];//最小深度點的編號}int p=lca(mn,mx);// 向上標記求lcaif((dep[mx]+2*dep[p]-dep[mn])%2){cout<<"NO\n";continue;}int deps=(dep[mx]+2*dep[p]-dep[mn])/2;int k=dep[mx]-deps;int s=mx;while(k--) s=fa[s];dfs(s,0);bool ok=1;for(int i=2;i<=m;i++)if(dep[c[i]]!=dep[c[i-1]]) {ok=0;break;}if(ok) {cout<<"YES\n";cout<<s<<'\n';}else cout<<"NO\n";}return 0;}J - Just the Last Digit
對于任意兩個點iii,jjj來說,兩個點是否存在一條邊最終只可能有1條路徑的差別,因此只需要知道路徑個數的最后一位即可區分是否該兩點直接有直接路徑相連。
對于兩個點之間的路徑個數我們可以根據遞推求出
考慮i→ji\to ji→j直接的路徑條數
我們可以考慮枚舉中間點kkk,i→k→?→ji\to k\to \dots \to ji→k→?→j(注意i→ki\to ki→k這條路徑是表示直接路徑不是間接路徑)不難得出i→ji\to ji→j路徑個數cnti→j=∑k=i+1j?1cntk→j(i→k)cnt_{i\to j}=\sum_{k=i+1}^{j-1}{cnt_{k\to j}}(i\to k)cnti→j?=∑k=i+1j?1?cntk→j?(i→k)
如果當前所求cnti→jcnt_{i\to j}cnti→j?與題中所給路徑個數有出處那么說明i→ji\to ji→j存在直接路徑,否則不存在。
我看到這個題給的條件時根本無從下述,我心里想給我路徑個數可能都不會求,題目中只給了路徑個數%10的結果。
當時心里一直在想一個公式cnti→j=cnti→k×cntk→jcnt_{i\to j}=cnt_{i\to k}×cnt_{k\to j}cnti→j?=cnti→k?×cntk→j?,這里kkk是iii與jjj之間任意一個點即可,而沒想的上述計數的方法。
H - High Load Database
隊友想的,二分+二分兩個log,由于記憶化不會被數據卡掉。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #pragma GCC optimize(2) #include<set> #include<map> #include<cmath> #include<queue> #include<random> #include<bitset> #include<string> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<unordered_map> #include<unordered_set> using namespace std; typedef long long ll; typedef pair<int,int> pii; const int N=1000010; ll a[N],s[N]; int ans[N]; int n; ll mx; void solve(int t) {ans[t]=0;if(t<mx) return; for(int i=1;i<=n;i++){int l=i,r=n;while(l<r){int mid=l+r+1>>1;if(s[mid]-s[i-1]<=t) l=mid;else r=mid-1;}i=r;ans[t]++;} } int main() {IO;int T=1;//cin>>T;while(T--){cin>>n;for(int i=1;i<=n;i++){cin>>a[i];mx=max(mx,a[i]);s[i]=s[i-1]+a[i];}int q;cin>>q;memset(ans,-1,sizeof ans);while(q--){int t;cin>>t;if(ans[t]!=-1) {if(ans[t]) cout<<ans[t]<<'\n';else cout<<"Impossible"<<'\n';}else{solve(t);if(ans[t]) cout<<ans[t]<<'\n';else cout<<"Impossible"<<'\n';}}}return 0;}總結
以上是生活随笔為你收集整理的ICPC 2019-2020 North-Western Russia Regional Contest 补题部分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 牛客小白月赛 27部分题解
- 下一篇: 演员吴玉华简介 演员吴玉华介绍