2018“百度之星”程序設計大賽 - 復賽
沒有兄弟的舞會
Accepts: 928 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description度度熊、光羽、帶勁三個人是好朋友。
度度熊有一棵nn個點的有根樹,其中1號點為樹根。除根節點之外,每個點都有父節點,記ii號點的父節點為fa[i]fa[i]。
度度熊稱點ii和點jj是兄弟(其中i \neq ji≠j)當且僅當fa[i]=fa[j]fa[i]=fa[j]。
第ii個點的權值為A_iA?i??。現要求選出一個點集,該點集合法當且僅當點集中至多只有一對兄弟。
度度熊想知道,在所有可行的點集中,權值和最大以及最小的點集權值和分別是多少?
Input第一行一個數,表示數據組數TT。
每組數據第一行一個整數nn;第二行n-1n?1個數,表示fa[2],fa[3],..,fa[n]fa[2],fa[3],..,fa[n];第三行nn個數,表示A_iA?i??。
數據組數T=100,滿足:
- 1 \le n \le 10^51≤n≤10?5??
- -10^9 \le A_i \le 10^9?10?9??≤A?i??≤10?9??
- 1 \le fa[i] < i1≤fa[i]<i
其中90%的數據滿足n \le 1000n≤1000。
Output每組數據輸出一行,每行包含兩個數,分別表示權值和的最大值和最小值。
2 5 1 1 2 2 -4 -4 -1 -2 -5 5 1 1 3 2 -1 -4 2 0 -2Sample Output
0 -15 2 -7
這個對我來說有點hard啊,我比較傻,要選的是點集,不一定是子樹,所以即使是樹形dp也不是全都可以選的,所以可以直接sort之後取一個就好了
另外一個直接找就好了
#include<stdio.h> #include<bits/stdc++.h> using namespace std; #define lson l,(l+r)/2,rt<<1 #definerson (l+r)/2+1,r,rt<<1|1 #define dbg(x) cout<<#x<<" = "<< (x)<< endl #define pb push_back #define fi first #define se second #define ll long long #define sz(x) (int)(x).size() #define pll pair<long long,long long> #define pii pair<int,int> #define pq priority_queue const int N=1e5+5,MD=1e9+7,INF=0x3f3f3f3f; const ll LL_INF=0x3f3f3f3f3f3f3f3f; const double eps=1e-9,e=exp(1),PI=acos(-1.); vector<ll>G[N]; ll a[N],x; int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int T,n; cin>>T; while(T--) { cin>>n; for(int i=2; i<=n; i++)cin>>a[i]; for(int i=1; i<=n; i++)cin>>x,G[a[i]].push_back(x); ll ma=0,mi=0,minx=1e9,maxx=-1e9; for(int i=0; i<=n; i++) { sort(G[i].begin(),G[i].end()); int len=G[i].size(); if(len) { ma=max(ma,ma+G[i][len-1]),mi=min(mi,mi+G[i][0]); if(len>1)minx=min(minx,G[i][1]),maxx=max(maxx,G[i][len-2]); } } mi=min({mi,mi+minx,0LL}),ma=max({ma,maxx+ma,0LL}); cout<<ma<<" "<<mi<<"\n"; for(int i=0; i<=n; i++)G[i].clear(); } return 0; }
帶勁的and和
Accepts: 791 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description度度熊專門研究過“動態傳遞閉包問題”,他有一萬種讓大家爆蛋的方法;但此刻,他只想出一道簡簡單單的題——至繁,歸於至簡。
度度熊有一張n個點m條邊的無向圖,第ii個點的點權為v_iv?i??。
如果圖上存在一條路徑使得點ii可以走到點jj,則稱i,ji,j是帶勁的,記f(i,j)=1f(i,j)=1;否則f(i,j)=0f(i,j)=0。顯然有f(i,j) = f(j,i)f(i,j)=f(j,i)。
度度熊想知道求出: \sum_{i=1}^{n-1} \sum_{j=i+1}^{n} f(i,j) \times \max(v_i, v_j) \times (v_i \& v_j)∑?i=1?n?1??∑?j=i+1?n??f(i,j)×max(v?i??,v?j??)×(v?i??&v?j??)
其中\&&是C++中的and位運算符,如1&3=1, 2&3=2。
請將答案對10^9+710?9??+7取模後輸出。
Input第一行一個數,表示數據組數TT。
每組數據第一行兩個整數n,mn,m;第二行nn個數表示v_iv?i??;接下來mm行,每行兩個數u,vu,v,表示點uu和點vv之間有一條無向邊。可能有重邊或自環。
數據組數T=50,滿足:
- 1 \le n,m \le 1000001≤n,m≤100000
- 1 \le v_i \le 10^91≤v?i??≤10?9??。
其中90%的數據滿足n,m \le 1000n,m≤1000。
Output每組數據輸出一行,每行僅包含一個數,表示帶勁的and和。
Sample Input1 5 5 3 9 4 8 9 2 1 1 3 2 1 1 2 5 2Sample Output
99
其實就是每一個聯通塊要算貢獻,這個聯通塊是可以用二進制壓縮的,所以並查集找出聯通塊直接暴力就好了
#include<stdio.h> #include<bits/stdc++.h> using namespace std; #define lson l,(l+r)/2,rt<<1 #define rson (l+r)/2+1,r,rt<<1|1 #define dbg(x) cout<<#x<<" = "<< (x)<< endl #define pb push_back #define fi first #define se second #define ll long long #define sz(x) (int)(x).size() #define pll pair<long long,long long> #define pii pair<int,int> #define pq priority_queue const int N=1e5+5,MD=1e9+7,INF=0x3f3f3f3f; const ll LL_INF=0x3f3f3f3f3f3f3f3f; const double eps=1e-9,e=exp(1),PI=acos(-1.); int fa[N],v[N]; vector<int>G[N]; int find(int x) { return x==fa[x]?x:(fa[x]=find(fa[x])); } void la(int x,int y) { x=find(x),y=find(y); if(x!=y)fa[x]=y; } int bit[31]; ll lb(vector<int>v) { sort(v.begin(),v.end()); ll ans=0,sum[31]= {0}; for(auto t:v) for(int j=0; j<30; j++) { if(t&bit[j]) { ans=(ans+t*1LL*sum[j]%MD*bit[j]%MD)%MD; sum[j]++; } } return ans; } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); for(int i=0; i<30; i++)bit[i]=1<<i; int T,n,m; cin>>T; while(T--) { cin>>n>>m; for(int i=1; i<=n; i++)cin>>v[i]; for(int i=1; i<=n; i++)fa[i]=i; for(int i=0,u,v; i<m; i++) cin>>u>>v,la(u,v); for(int i=1; i<=n; i++)G[find(i)].push_back(v[i]); int ans=0; for(int i=1; i<=n; i++) { if(G[i].size()==0)continue; ans=(ans+lb(G[i]))%MD; } cout<<ans<<"\n"; for(int i=1; i<=n; i++)G[i].clear(); } return 0; }
序列期望
Accepts: 545 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description"看似隨機,實則早已註定"——光羽
度度熊有nn個隨機變量x_1,x_2,...,x_nx?1??,x?2??,...,x?n??。給定區間[l_1, r_1],...,[l_n, r_n][l?1??,r?1??],...,[l?n??,r?n??],變量x_ix?i??的值會等概率成為區間[l_i, r_i][l?i??,r?i??]中的任意一個整數。
顯然這nn個隨機變量的值會有一共\prod_{i=1}^{n} (r_i - l_i + 1)∏?i=1?n??(r?i???l?i??+1) 種情況,且每種情況出現的概率為\prod_{i=1}^{n} \frac{1}{r_i - l_i + 1}∏?i=1?n???r?i???l?i??+1??1?? 。
對於某種情況,令h= \max{ x_1,x_2,...,x_n}h=max{x?1??,x?2??,...,x?n??},定義這種情況的權值為:\prod_{i=1}^{n} (h - x_i + 1)∏?i=1?n??(h?x?i??+1).
度度熊想知道權值的期望是多少?請將答案對10^9 + 710?9??+7取模後輸出。
PS:不清楚期望是啥?為什麽不問問神奇的百度呢?
Input第一行一個數,表示數據組數TT。
每組數據第一行一個整數nn;接下來nn行,每行兩個數,表示l_il?i??和r_ir?i??。
數據組數T=100,滿足:
- 1 \le n \le 1001≤n≤100
- 1 \le l_i \le r_i \le 10^41≤l?i??≤r?i??≤10?4??
其中70%的數據滿足r_i \le 100r?i??≤100。
Output每組數據輸出一行,每行僅包含一個數,表示期望。
假設答案為\frac{p}{q}?q??p??,請輸出p \times q^{-1} ~mod~10^9+7p×q??1?? mod 10?9??+7,此處q^{-1}q??1??為qq的逆元。
Sample Input2 3 2 5 2 4 2 5 3 1 1 2 3 1 1Sample Output
875000012 500000010Hint 第二組數據的解釋:序列只有兩種情況(1,2,1)和(1,3,1),權值分別為2*1*2=4和3*1*3=9,答案為(4+9)/2,在模域下為500000010。 這個題目看起來好像不可做,其實就是簡單的期望,我們只要想到權值的統計方法就好了 顯然我們可以枚舉最大的區間
2018“百度之星”程序設計大賽 - 復賽