CF1388A~D(DFS,拓撲排序)
阿新 • • 發佈:2020-07-31
A.Captain Flint and Crew Recruitment
題意:
定義了一種近似素數,當一個數可以用兩個素數的乘積表示時,稱他為近似素數。
現在請你把正整數n用四個不同的正整數的和表示,其中至少三個是近似素數。
題解:
直接分解成三個最小的近似素數和另外一個隨便什麼數的和即可。
#include<bits/stdc++.h> using namespace std; int t,n; int main () { scanf("%d",&t); while (t--) { scanf("%d",&n);View Codeif (n<=30) { printf("NO\n"); continue; } printf("YES\n"); //printf("6 10 14 %d\n",n-20); if (n-30==6||n-30==10||n-30==14) { printf("6 10 15 %d\n",n-31); } else { printf("6 10 14 %d\n",n-30); } } }
B.Captain Flint and a Long Voyage
題意:
給出一個長度n,請你找到最小的長度為n的十進位制數x,使得它轉換為2進位制後的的數去掉最後n位儘可能大。
題解:
測智題,對我這種智商低的選手不友好。答案就是前3/4是9,後1/4是8。
#include<bits/stdc++.h> using namespace std; const int maxn=11010; int t,n; int main () { scanf("%d",&t); while (t--) { scanf("%d",&n);View Codeint tt=n/4; if (n%4) tt++; for (int i=1;i<=n-tt;i++) printf("9"); for (int i=n-tt+1;i<=n;i++) printf("8"); printf("\n"); } }
C.Uncle Bogdan and Country Happiness
題意:
給出一棵樹,每個節點代表一個城市,每個城市有人口。一開始所有人都在首都1。
給出一個序列h,表示猜測的每個城市的開心人數和不開心人數的差值。
現在所有人從首都1開始返回自己的家鄉,他們保持同步,到自己家鄉之後會停止,他們可以在任意時刻改變自己的心情,但變成不開心之後就永遠不開心了。
詢問是否可能h陣列的情況出現。
題解:
首先統計出每個節點的子樹人口數,以此排除無法構造差值的節點(比如奇偶性不同就無法構造)
然後通過給定的h[i]算出每個節點開心的人數,然後做第二遍DFS,看一下每個節點的開心的人數和它所有子節點的開心的人數之和,如果小於則不合法。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+100; vector<int> g[maxn]; typedef long long ll; ll p[maxn]; ll h[maxn]; ll dfn[maxn];//記錄每個城市的子樹人口和 ll wjm[maxn];//計算出每個節點必須開心的人數 int t,n,m; int f; void dfs (int u,int pre) { dfn[u]=p[u]; for (int v:g[u]) { if (v==pre) continue; dfs(v,u); dfn[u]+=dfn[v]; } } void dfs1 (int u,int pre) { int sum=0; for (int v:g[u]) { if (v==pre) continue; dfs1(v,u); sum+=wjm[v]; } //printf("%d %d %d\n",u,wjm[u],sum); if (sum>wjm[u]) f=0; } int main () { scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) g[i].clear(),dfn[i]=0; for (int i=1;i<=n;i++) scanf("%lld",p+i); for (int i=1;i<=n;i++) scanf("%lld",h+i); for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); g[x].push_back(y); g[y].push_back(x); } dfs(1,0); f=1; for (int i=1;i<=n;i++) { // printf("%d %d\n",dfn[i],h[i]); //if (dfn[i]-2*abs(h[i])<0) f=0; if (dfn[i]<h[i]||dfn[i]<-h[i]) f=0; if ((dfn[i]%2)^(abs(h[i])%2)) f=0; ll x=(dfn[i]+h[i])>>1; wjm[i]=x; } dfs1(1,0); if (f) printf("YES\n"); else printf("NO\n"); } }View Code
D.Captain Flint and Treasure
題意:
給出兩個序列a和b,一次操作你可以將ans+=a[i],a[b[i]]+=a[i]。詢問最後ans的最大值。
題解:
拓撲排序,遇到負權值的節點就跳過,減少它給答案帶來的貢獻。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+100; typedef long long ll; ll a[maxn]; int b[maxn]; int inDegree[maxn]; int n; vector<int> g[maxn]; ll ans; void topo () { queue<int> q; for (int i=1;i<=n;i++) if (inDegree[i]==0) { q.push(i); } while (!q.empty()) { int u=q.front(); q.pop(); ans+=a[u]; if (b[u]==-1) continue; if (a[u]>0) { g[u].push_back(b[u]); a[b[u]]+=a[u]; } else { g[b[u]].push_back(u); } if (--inDegree[b[u]]==0) q.push(b[u]); } } int main () { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%lld",a+i); for (int i=1;i<=n;i++) { scanf("%d",b+i); if (b[i]>0) { inDegree[b[i]]++; } } topo(); printf("%lld\n",ans); vector<int> wjm; for (int i=1;i<=n;i++) for (int v:g[i]) inDegree[v]++; for (int i=1;i<=n;i++) if (inDegree[i]==0) wjm.push_back(i); for (int i=0;i<n;i++) { printf("%d ",wjm[i]); for (int v:g[wjm[i]]) if (--inDegree[v]==0) wjm.push_back(v); } }View Code