没有兄弟的舞会
度度熊、光羽、带劲三个人是好朋友。
度度熊有一棵nn个点的有根树,其中1号点为树根。除根节点之外,每个点都有父节点,记ii号点的父节点为fa[i]fa[i]。
度度熊称点ii和点jj是兄弟(其中i \neq ji≠j)当且仅当fa[i]=fa[j]fa[i]=fa[j]。
第ii个点的权值为A_iAi。现要求选出一个点集,该点集合法当且仅当点集中至多只有一对兄弟。
度度熊想知道,在所有可行的点集中,权值和最大以及最小的点集权值和分别是多少?
第一行一个数,表示数据组数TT。
每组数据第一行一个整数nn;第二行n-1n−1个数,表示fa[2],fa[3],..,fa[n]fa[2],fa[3],..,fa[n];第三行nn个数,表示A_iAi。
数据组数T=100,满足:
- 1 \le n \le 10^51≤n≤105
- -10^9 \le A_i \le 10^9−109≤Ai≤109
- 1 \le fa[i] < i1≤fa[i]<i
其中90%的数据满足n \le 1000n≤1000。
每组数据输出一行,每行包含两个数,分别表示权值和的最大值和最小值。
2 5 1 1 2 2 -4 -4 -1 -2 -5 5 1 1 3 2 -1 -4 2 0 -2
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 #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.); 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和
度度熊专门研究过“动态传递闭包问题”,他有一万种让大家爆蛋的方法;但此刻,他只想出一道简简单单的题——至繁,归于至简。
度度熊有一张n个点m条边的无向图,第ii个点的点权为v_ivi。
如果图上存在一条路径使得点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=1n−1∑j=i+1nf(i,j)×max(vi,vj)×(vi&vj)
其中\&&是C++中的and位运算符,如1&3=1, 2&3=2。
请将答案对10^9+7109+7取模后输出。
第一行一个数,表示数据组数TT。
每组数据第一行两个整数n,mn,m;第二行nn个数表示v_ivi;接下来mm行,每行两个数u,vu,v,表示点uu和点vv之间有一条无向边。可能有重边或自环。
数据组数T=50,满足:
- 1 \le n,m \le 1000001≤n,m≤100000
- 1 \le v_i \le 10^91≤vi≤109。
其中90%的数据满足n,m \le 1000n,m≤1000。
每组数据输出一行,每行仅包含一个数,表示带劲的and和。
1 5 5 3 9 4 8 9 2 1 1 3 2 1 1 2 5 2
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; }
序列期望
"看似随机,实则早已注定"——光羽
度度熊有nn个随机变量x_1,x_2,...,x_nx1,x2,...,xn。给定区间[l_1, r_1],...,[l_n, r_n][l1,r1],...,[ln,rn],变量x_ixi的值会等概率成为区间[l_i, r_i][li,ri]中的任意一个整数。
显然这nn个随机变量的值会有一共\prod_{i=1}^{n} (r_i - l_i + 1)∏i=1n(ri−li+1) 种情况,且每种情况出现的概率为\prod_{i=1}^{n} \frac{1}{r_i - l_i + 1}∏i=1nri−li+11 。
对于某种情况,令h= \max{ x_1,x_2,...,x_n}h=max{x1,x2,...,xn},定义这种情况的权值为:\prod_{i=1}^{n} (h - x_i + 1)∏i=1n(h−xi+1).
度度熊想知道权值的期望是多少?请将答案对10^9 + 7109+7取模后输出。
PS:不清楚期望是啥?为什么不问问神奇的百度呢?
第一行一个数,表示数据组数TT。
每组数据第一行一个整数nn;接下来nn行,每行两个数,表示l_ili和r_iri。
数据组数T=100,满足:
- 1 \le n \le 1001≤n≤100
- 1 \le l_i \le r_i \le 10^41≤li≤ri≤104
其中70%的数据满足r_i \le 100ri≤100。
每组数据输出一行,每行仅包含一个数,表示期望。
假设答案为\frac{p}{q}qp,请输出p \times q^{-1} ~mod~10^9+7p×q−1 mod 109+7,此处q^{-1}q−1为qq的逆元。
2 3 2 5 2 4 2 5 3 1 1 2 3 1 1
875000012 500000010
#include<stdio.h> #include<algorithm> typedef long long ll; const int MD=1e9+7; int l[105],r[105]; ll w[105],v[10002]; int main() { v[0]=v[1]=1; for(int i=2; i<10002; i++)v[i]=v[MD%i]*(MD-MD/i)%MD; int T,n,m; scanf("%d",&T); while(T--) { int L=0,R=0; ll ans=0; scanf("%d",&n); for(int i=0; i<n; i++)scanf("%d%d",&l[i],&r[i]),L=std::max(L,l[i]),R=std::max(R,r[i]); auto la=[&](long long x, long long y) { return (x+y)*(y-x+1)%MD*v[2]%MD; }; for(int i=L; i<=R; i++) { ll t=1; w[n]=1; for(int j=0,x,y; j<n; j++) { x=std::max(2,i-r[j]+1),y=i-l[j]+1; w[j]=la(x,y); } for(int j=n-1; j>=0; j--)w[j]=w[j]*w[j+1]%MD; for(int j=0,x,y; j<n; j++) { if(r[j]>=i)ans=(ans+t*w[j+1])%MD; x=std::max(1,i-r[j]+1),y=i-l[j]+1; t=t*la(x,y)%MD; } } for(int i=0; i<n; i++)ans=ans*v[r[i]-l[i]+1]%MD; printf("%lld\n",ans); } return 0; }
前面一定是2的倍数,为什么要乘上逆元,sb了,这样就不被卡常了
#include<stdio.h> #include<algorithm> typedef long long ll; const int MD=1e9+7; int l[105],r[105]; ll w[105],v[10002]; ll la(ll x,ll y) { return (x+y)*(y-x+1)/2%MD; } int main() { v[0]=v[1]=1; for(int i=2; i<10002; i++)v[i]=v[MD%i]*(MD-MD/i)%MD; int T,n,m; scanf("%d",&T); while(T--) { int L=0,R=0; ll ans=0; scanf("%d",&n); for(int i=0; i<n; i++)scanf("%d%d",&l[i],&r[i]),L=std::max(L,l[i]),R=std::max(R,r[i]); for(int i=L; i<=R; i++) { ll t=1; w[n]=1; for(int j=0,x,y; j<n; j++) { x=std::max(2,i-r[j]+1),y=i-l[j]+1; w[j]=la(x,y); } for(int j=n-1; j>=0; j--)w[j]=w[j]*w[j+1]%MD; for(int j=0,x,y; j<n; j++) { if(r[j]>=i)ans=(ans+t*w[j+1])%MD; x=std::max(1,i-r[j]+1),y=i-l[j]+1; t=t*la(x,y)%MD; } } for(int i=0; i<n; i++)ans=ans*v[r[i]-l[i]+1]%MD; printf("%lld\n",ans); } return 0; }