zoukankan      html  css  js  c++  java
  • 2021-06-18 集训题解

    今天爆傻了

    T1 种蘑菇

    题目传送门

    Description

    有一个 (n) 个点的树,问 (sum gcd{S}^{|S|}),其中 (S) 是树上的一个连通块。

    (nle 10^5),答案对 (10^9+7) 取模。

    Solution

    很水,可惜我是zz。。。

    可以想到,如果我们设 (f_{k,i}) 表示 (i|gcd{S})(S)(k^{|S|}) 之和,那么答案就是:

    [sum_{k=1}^{n} sum_{i=1}^{lfloorfrac{n}{k} floor}mu(i) imes f_{k,i imes k} ]

    (f_{k,i}) 可以直接树形dp,在 (k,i) 确定时可以列出 (f_u o f_u imes (f_v+1),vin Son_u) 的转移式。

    复杂度 (Theta(nln^2n))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 1000000007
    #define MAXN 200005
    
    template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
    template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
    template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> void chkmin (T &a,T b){a = min (a,b);}
    
    int n;
    vector <int> G[MAXN];
    void link (int u,int v){
    	G[u].push_back (v),
    	G[v].push_back (u);
    }
    
    int mul (int a,int b){return 1ll * a * b % mod;}
    int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
    int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
    int qkpow (int a,int b){
    	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
    	return res;
    }
    int inv (int x){return qkpow (x,mod - 2);}
    void Add (int &a,int b){a = add (a,b);}
    int gcd (int a,int b){return !b ? a : gcd (b,a % b);}
    int lcm (int a,int b){return a / gcd (a,b) * b;}
    
    bool vis[MAXN];
    int tot,mu[MAXN],prime[MAXN];
    void Euler (){
    	mu[1] = 1;
    	for (Int i = 2;i <= n;++ i){
    		if (!vis[i]) prime[++ tot] = i,mu[i] = -1;
    		for (Int j = 1;j <= tot && i * prime[j] <= n;++ j){
    			vis[i * prime[j]] = 1;
    			if (i % prime[j]) mu[i * prime[j]] = -mu[i];
    			else break;
    		}
    	}
    } 
    
    int ind,q[MAXN],dfn[MAXN];
    
    void init (int u,int fa){
    	dfn[u] = ++ ind;
    	for (Int v : G[u]) if (v ^ fa) init (v,u);
    }
    
    bool visit[MAXN];
    int K,S,res,f[MAXN];
    void dfs (int u,int fa){
    	f[u] = K,visit[u] = 1;
    	for (Int v : G[u]) if (v != fa && v % S == 0) dfs (v,u),f[u] = mul (f[u],f[v] + 1);
    	Add (res,f[u]);
    }
    
    int getit (){
    	int len = n / S;res = 0;
    	for (Int i = 1;i <= len;++ i) q[i] = i * S;
    	sort (q + 1,q + len + 1,[](int x,int y){return dfn[x] < dfn[y];});
    	for (Int i = 1;i <= len;++ i) if (!visit[q[i]]) dfs (q[i],0);
    	for (Int i = 1;i <= len;++ i) visit[q[i]] = 0;
    	return res;
    }
    
    signed main(){
      freopen("mushroom.in", "r", stdin);
      freopen("mushroom.out", "w", stdout);
    	read (n),Euler ();
    	for (Int i = 2,u,v;i <= n;++ i) read (u,v),link (u,v);
    	init (1,0);int ans = 0;
    	for (K = 1;K <= n;++ K)
    		for (Int i = 1;i <= n / K;++ i)
    			if (mu[i]){
    				S = i * K;
    				int tmp = getit ();
    				if (mu[i] > 0) Add (ans,tmp);
    				else ans = dec (ans,tmp);
    			}
    	write (ans),putchar ('
    ');
    	return 0;
    }
    

    T2 轮回

    题目传送门

    Description

    并不是很想搬。

    Solution

    可以想到设 (f_{i,j}) 表示到了第 (i) 个节点,离中心线距离为 (j) 时还要走的期望长度,可以列出转移式:

    [ ext{when j} ot= 0:f_{i,j}=1+p_i imes f_{i+1,j}+frac{1-p_i}{2} imes f_{i+1,j-1}+frac{1-p_i}{2} imes f_{i+1,j+1} ]

    [ ext{when} j=0:f_{i,j}=1+p_i imes f_{i+1,j}+(1-p_i) imes f_{i+1,j-1} ]

    边界条件即是 (f_{i,k+1}=0)

    然后我们看出,这个转移式可以写成矩阵乘法,即 (F_i=M_i imes F_{i+1}),那么我们就可以得到 (F_x=M_x imes M_{x+1} imes ... imes M_n imes M_1 imes ... imes M_{x-1} imes F_x)

    那么我们就可以高斯消元。矩阵乘法部分可以线段树优化。复杂度 (Theta(nk^3log n))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define inv2 500000004
    #define mod 1000000007
    #define MAXN 100005
    #define MAXM 8
    
    template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
    template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
    template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> void chkmin (T &a,T b){a = min (a,b);}
    
    int n,K,q,a[MAXN],b[MAXN],p[MAXN];
    int mul (int a,int b){return 1ll * a * b % mod;}
    int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
    int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
    int qkpow (int a,int b){
    	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
    	return res;
    }
    int inv (int x){return qkpow (x,mod - 2);}
    void Add (int &a,int b){a = add (a,b);}
    
    struct Matrix{
    	int val[MAXM][MAXM];
    	Matrix(){memset (val,0,sizeof (val));}
    	int * operator [](int key){return val[key];}
    	Matrix operator * (const Matrix &p)const{
    		Matrix New;
    		for (Int i = 0;i <= K + 1;++ i)	
    			for (Int j = 0;j <= K + 1;++ j)
    				for (Int k = 0;k <= K + 1;++ k)
    					Add (New[i][k],mul (val[i][j],p.val[j][k]));
    		return New;
    	}
    	void putout (){
    		cout << " --------------- " << endl;
    		for (Int i = 0;i <= K + 1;++ i){
    			for (Int j = 0;j <= K + 1;++ j)
    				cout << val[i][j] << " ";
    			cout << endl;
    		}
    		cout << " ------------ " << endl;
    	}
    };
    
    struct Segment{
    	Matrix Sum[MAXN << 2];
    	void buildit (int x,int l){
    		Sum[x][0][0] = p[l],Sum[x][0][1] = dec (1,p[l]);
    		for (Int i = 1;i <= K;++ i){
    			Sum[x][i][i] = p[l],Sum[x][i][i - 1] = mul (inv2,dec (1,p[l]));
    			if (i != K) Sum[x][i][i + 1] = Sum[x][i][i - 1];
    		}
    		for (Int i = 0;i <= K + 1;++ i) Sum[x][i][K + 1] = 1;		
    	}
    	void pushup (int x){Sum[x] = Sum[x << 1] * Sum[x << 1 | 1];}
    	void build (int x,int l,int r){
    		if (l == r) return buildit (x,l);
    		int mid = (l + r) >> 1;
    		build (x << 1,l,mid),build (x << 1 | 1,mid + 1,r),pushup (x);
    	}
    	Matrix query (int x,int l,int r,int ql,int qr){
    		if (ql > qr){
    			Matrix res;
    			for (Int i = 0;i <= K + 1;++ i) res[i][i] = 1;
    			return res;
    		}
    		if (l >= ql && r <= qr) return Sum[x];
    		int mid = (l + r) >> 1;Matrix res;
    		for (Int i = 0;i <= K + 1;++ i) res[i][i] = 1;
    		if (ql <= mid) res = res * query (x << 1,l,mid,ql,qr);
    		if (qr > mid) res = res * query (x << 1 | 1,mid + 1,r,ql,qr);
    		return res;
    	}
    	void change (int x,int l,int r,int pos){
    		if (l == r) return buildit (x,l);
    		int mid = (l + r) >> 1;
    		if (pos <= mid) change (x << 1,l,mid,pos);
    		else change (x << 1 | 1,mid + 1,r,pos);
    		pushup (x);
    	}
    }Tree;
    
    int A[MAXM][MAXM],tmp[MAXM];
    int Gaussit (){
    	int up = K;
    	for (Int i = 0;i <= up;++ i){
    		int pos = i;
    		for (Int j = i;j <= up;++ j) if (A[j][i] > A[pos][i]){pos = j;break;}
    		if (pos ^ i) swap (A[i],A[pos]);int iv = inv (A[i][i]);
    		for (Int j = i + 1;j <= up;++ j){
    			int det = mul (A[j][i],iv);
    			for (Int k = i;k <= up + 1;++ k) A[j][k] = dec (A[j][k],mul (det,A[i][k]));
    		} 
    	}
    	for (Int i = up;i >= 0;-- i){
    		int fuc = A[i][up + 1];
    		for (Int j = up;j > i;-- j) fuc = dec (fuc,mul (A[i][j],tmp[j]));
    		tmp[i] = mul (fuc,inv (A[i][i]));
    	} 	
    	return tmp[0];
    }
    
    int Solve (int x){
    	Matrix res = Tree.query (1,1,n,x,n) * Tree.query (1,1,n,1,x - 1);
    //	res.putout();
    	for (Int i = 0;i <= K;++ i){
    		for (Int j = 0;j <= K;++ j) A[i][j] = res[i][j];
    		A[i][i] --,A[i][K + 1] = mod - res[i][K + 1];
    	} 
    	return Gaussit ();
    }
    
    signed main(){
      	freopen("samsara.in", "r", stdin);
      	freopen("samsara.out", "w", stdout);
      	read (n,K,q);
      	for (Int i = 1;i <= n;++ i) read (a[i],b[i]),p[i] = mul (a[i],inv (b[i]));
      	Tree.build (1,1,n);
    	while (q --> 0){
    		int kase,i;read (kase,i);
    		if (kase == 1) write (Solve (i)),putchar ('
    ');
    		else{
    			int a,b;read (a,b);
    			p[i] = mul (a,inv (b)),Tree.change (1,1,n,i); 
    		}
    	} 
    	return 0;
    }
    

    T3 洞

    题目传送门

    Description

    还是懒得搬。

    Solution

    假设一个球距离两边最近的距离为 (x,y),那么我们可以把它看作一个点 ((x,y))

    可以想到的是,如果对于点 ((x2,y2)) 存在点 ((x1,y1)),是的 ((x1,y1))((x2,y2)) 左上方,那么如果 ((x1,y1)) 是掉进右侧,则 (x2,y2) 也是掉进右侧。

    发现当且仅当满足该规则时存在解。所以我们可以统计不同的严格上升子序列,即是答案。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 1000000007
    #define MAXN 100005
    
    template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
    template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
    template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> void chkmin (T &a,T b){a = min (a,b);}
    
    int mul (int a,int b){return 1ll * a * b % mod;}
    int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
    int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
    int qkpow (int a,int b){
    	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
    	return res;
    }
    int inv (int x){return qkpow (x,mod - 2);}
    void Add (int &a,int b){a = add (a,b);}
    
    #define pii pair<int,int>
    pii f[MAXN];
    int n,m,cnt,uni,s[MAXN],xh[MAXN],yh[MAXN],tmp[MAXN];
    
    int val[MAXN];
    int lowbit(int x){return x & (-x);}
    void modify (int x,int v){for (Int i = x;i <= n;i += lowbit (i)) Add (val[i],v);}
    int query (int x){int res = 0;for (Int i = x;i;i -= lowbit (i)) Add (res,val[i]);return res;}
    
    bool cmp (pii A,pii B){
    	return A.first != B.first ? A.first < B.first : A.second > B.second;
    }
    
    signed main(){
    	freopen ("hole.in","r",stdin);
    	freopen ("hole.out","w",stdout);
    	read (n,m);
    	for (Int i = 1;i <= n;++ i) read (xh[i]);
    	for (Int i = 1;i <= m;++ i) read (yh[i]);
    	for (Int i = 1;i <= n;++ i) 
    		if (xh[i] > yh[1] && xh[i] < yh[m]){
    			int pos = lower_bound (yh + 1,yh + m + 1,xh[i]) - yh;
    			if (yh[pos] == xh[i]) continue;
    			int x = xh[i] - yh[pos - 1],y = yh[pos] - xh[i];
    			f[++ cnt] = make_pair (x,y);
    		}
    	sort (f + 1,f + cnt + 1,cmp),cnt = unique(f + 1,f + cnt + 1) - f - 1;
    	for (Int i = 1;i <= cnt;++ i) s[i] = f[i].second,tmp[i] = s[i];
    	sort (tmp + 1,tmp + cnt + 1),uni = unique (tmp + 1,tmp + cnt + 1) - tmp - 1;
    	for (Int i = 1;i <= cnt;++ i) s[i] = lower_bound (tmp + 1,tmp + uni + 1,s[i]) - tmp;
    	int ans = 1;
    	for (Int i = 1;i <= cnt;++ i){
    		int tmp = query (s[i] - 1) + 1;
    		Add (ans,tmp),modify (s[i],tmp);
    	}
    	write (ans),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    flex学习网站地址
    ASP.NET 开发人员应该知道的8个网站
    登入页面添加图片有重复页面出现怎么办
    一行代码是有两个??
    c# 枚举基础有[flags]和没有的的区别
    c#中[Flags] 枚举类型定义问题_百度知道
    写出一条Sql语句:取出表A中第31到第40记录(SQLServer,以自动增长的ID作为主键,注意:ID可能不是连续的。
    Margin和Padding之间的区别
    对于top.ascx里面可以不可以放置css的文件进行一个讲解
    设计模式之--适配器模式(Adapter)
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/14900208.html
Copyright © 2011-2022 走看看