G
题意:一棵树每个点权有一个,
可以作为
的中转站的条件如下。
在
之间的路径上。
-
可以是
之一。
-
需要不同。
-
-
定义点的承载量是
可以作为
的中转站的无序对
的个数。
最大化使得每个点的承载量小于
。
题解:二分。将
升序,按顺序依次将每个点塞到按照dfs序建立的树状数组上。
有一个坑点:需要根据 是
之一,
不是
之一进行分类讨论,需要考虑清楚
是
之一这个case。
H
题意:有种宝石,一次魔法可以把第
种宝石变成第
种宝石并且个数变成原来的
倍。每次询问最少需要多少次魔法可以把
个第
种宝石变成
个第种宝石。
数据范围:询问次数是次。
。
题解:
先用一个对数trick。
考虑矩阵快速幂表示进行
次魔法后第
种宝石到第
种宝石的最大翻倍数。
每次询问需要从高位到低位拼出答案。用和向量
相乘。
的大小是
。
表示当前次数下第
种宝石到第
种宝石的最大翻倍数。需要保证当前次数下第
种宝石的翻倍数小于
。拼出的二进制数是
。答案是
即翻倍数不小于
。
复杂度。
感想:确实是个好题,贴个代码。
#include<bits/stdc++.h>
using namespace std ;
typedef double db ;
typedef vector<db> vec ;
typedef vector<vec> mat ;
mat mul(mat &A , mat &B)
{
mat C(A.size() , vec(B[0].size() , -1e9)) ;
for(int i = 0 ; i < (int)A.size() ; i ++)
for(int j = 0 ; j < (int)B[0].size() ; j ++)
for(int k = 0 ; k < (int)A[0].size() ; k ++)
C[i][j] = max(C[i][j] , A[i][k] + B[k][j]) ;
return C ;
}
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int n , q ;
cin >> n >> q ;
mat a(n , vec(n)) ;
vector<mat> A(20 , mat(n , vec(n))) ;
for(int i = 0 ; i < n ; i ++)
for(int j = 0 ; j < n ; j ++)
cin >> a[i][j] ;
for(int i = 0 ; i < n ; i ++)
for(int j = 0 ; j < n ; j ++)
{
if(a[j][i] == 0) A[0][i][j] = -1e9 ;
else A[0][i][j] = log2(a[j][i]) ;
if(i == j) A[0][i][j] = 0 ;
}
for(int i = 1 ; i <= 19 ; i ++) A[i] = mul(A[i - 1] , A[i - 1]) ;
while(q --)
{
int x , k ;
cin >> x >> k ;
x -- ;
mat res(n , vec(1 , -1e9)) ;
res[x][0] = 0 ;
int ans = 0 ;
for(int i = 19 ; i >= 0 ; i --)
{
mat tmp = mul(A[i] , res) ;
if(tmp[x][0] < k) ans += (1 << i) , res = tmp ;
}
cout << ans + 1 << '\n' ;
}
return 0 ;
//you should actually read the stuff at the bottom before submitting or in the confusion
}
/* stuff you should look for
* long long
* array bounds
* init
* ios
* special cases (n=1?)
* do smth instead of nothing and stay organized
* WRITE STUFF DOWN
* DON'T GET STUCK ON ONE APPROACH
* DON'T GET STUCK ON ONE PROBLEM
*/
L
题意:每个点会发出两条射线,射线夹着的区域是合法区域。这样的点有n个。问n个合法区域交集的内接圆的半径。
题解:二分+半平面交。
感想:主要是这场没时间了,不会做这个的,即使是模板题。这场打的太差了。。。