2018-2019 ACM-ICPC, Asia Xuzhou Regional Contest
A Rikka with Minimum Spanning Trees
题目链接
题意:一个随机数生成器,然后随机生成u,v,w。求最小生成树。
思路:只要将生成的随机数跑最小生成树,并且判断所有点是否都联通即可。
#include <bits/stdc++.h>
#define maxn 100005
typedef unsigned long long ll;
using namespace std;
const int mod = 1e9 + 7;
unsigned long long k1,k2;
unsigned long long xorShift128Plus(){
unsigned long long k3=k1,k4=k2;
k1=k4;
k3^=k3<<23;
k2=k3^k4^(k3>>17)^(k4>>26);
return k2+k4;
}
int n,m,u[maxn],v[maxn];
unsigned long long w[maxn];
struct edge{
int u,v;
ll cost;
};
bool cmp(const edge &e1,const edge &e2){
return e1.cost<e2.cost;
}
int fa[maxn];
edge es[maxn];
void init(){
for(int i=1;i<=n;i++)
fa[i]=i;
}
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void mix(int x,int y){
int fx=find(x);
int fy=find(y);
fa[fx]=fy;
}
ll kruskal(){
sort(es+1,es+1+m,cmp);
init();
ll res=0;
for(int i=1;i<=m;i++){
edge e=es[i];
if(find(e.u)!=find(e.v)){
mix(e.u,e.v);
res=(res+e.cost%mod)%mod;
}
}
return res;
}
void gen(){
scanf("%d%d%llu%llu",&n,&m,&k1,&k2);
for(int i=1;i<=m;i++){
u[i]=xorShift128Plus()%n+1;
v[i]=xorShift128Plus()%n+1;
w[i]=xorShift128Plus();
es[i].u=u[i];
es[i].v=v[i];
es[i].cost=w[i];
}
ll ans=kruskal();
int flag=0;
for(int i=2;i<=n;i++)
if(find(1)!=find(i))
flag=1;
if(flag)
printf("0\n");
else
printf("%d\n",ans%mod);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
gen();
}
} G Rikka with Intersections of Paths
题目链接
题意:由n个点形成的树,有m个点对(u,v)代表标记的简单路径,问从中可以选择多少个集合大小为k,满足这k个集合至少有一个公共交点。
思路:模样例,可以得出结论,将m条路径上的点权+1,边权+1。最好答案为所有点点权t1的组合数和C(t1,k)-所有边边权t2的组合数和C(t2,k)。
通过树上差分实现点权加和边权加操作。套上组合数逆元板子。
用树链剖分实现边权加和点权加,时间复杂度为nloglogn。被卡掉了。
#include <bits/stdc++.h>
#define maxn 300005
#define maxn_log 30
typedef long long ll;
using namespace std;
const int MOD = 1000000007;
int n, m, k;
vector<int> G[maxn];
int root;
int fa[maxn_log][maxn];
int dep[maxn];
ll val[maxn];
ll val2[maxn];
ll fac[maxn];
ll inv[maxn];
ll invfac[maxn];
void initfac()
{
fac[1]=1;inv[1]=1;invfac[1]=1;
fac[0]=1;inv[0]=1;invfac[0]=1;
for(int i=2;i<maxn;i++)
{
fac[i]=fac[i-1]*i%MOD;
inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
invfac[i]=invfac[i-1]*inv[i]%MOD;
}
}
ll C(int n,int m)
{
return fac[n]*invfac[m]%MOD*invfac[n-m]%MOD;
}
void dfs(int v,int p,int d){
fa[0][v]=p;
dep[v] = d;
for (int i = 0;i<G[v].size();i++){
if(G[v][i]!=p)
dfs(G[v][i], v, d + 1);
}
}
void dfs(int u,int fa){
for (int i = 0; i < G[u].size();i++){
if(G[u][i]==fa)
continue;
dfs(G[u][i], u);
val[u] += val[G[u][i]];
val2[u] += val2[G[u][i]];
}
return;
}
void init(){
dfs(root, 0, 0);
for (int k = 0; k + 1 < maxn_log;k++){
for (int v = 1; v <= n;v++){
if(fa[k][v]==0)
fa[k + 1][v] = 0;
else
fa[k + 1][v] = fa[k][fa[k][v]];
}
}
memset(val,0,sizeof val);
memset(val2, 0, sizeof val2);
}
int lca(int u,int v){
if(dep[u]>dep[v])
swap(u, v);
for (int k = 0; k < maxn_log;k++){
if((dep[v]-dep[u])>>k&1){
v = fa[k][v];
}
}
if(u==v)
return u;
for (int k = maxn_log - 1; k >= 0;k--){
if(fa[k][u]!=fa[k][v]){
u = fa[k][u];
v = fa[k][v];
}
}
return fa[0][u];
}
void input(){
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n;i++)
G[i].clear();
for (int i = 1,u,v; i < n;i++){
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
root = 1;
init();
for (int i = 1,u,v; i <= m;i++){
scanf("%d%d", &u, &v);
int pos = lca(u, v);
val[u]++;
val[v]++;
val[pos]--;
val[fa[0][pos]]--;
val2[u]++;
val2[v]++;
val2[pos] -= 2;
}
}
void solve(){
dfs(1, -1);
ll ans=0;
for(int i=1;i<=n;i++){
if(val[i]>=k)
ans = (ans + C(val[i], k))%MOD;
}
for (int i = 2;i<=n;i++){
if(val2[i]>=k)
ans = (ans - C(val2[i], k) + MOD) % MOD;
}
printf("%lld\n", ans);
}
int main(){
int t;
initfac();
scanf("%d", &t);
while(t--){
input();
solve();
}
}
京公网安备 11010502036488号