# 2020牛客暑假多校训练二

## C.Cover the Tree

### 题解：

· 如果 $R\leq \frac{n}{2}$ 那么此边必定会被 $R - R+\frac{n}{2}$ 覆盖

· 如果 $L> \frac{n}{2}$ 那么此边必定会被 $L-\frac{n}{2} — L$ 覆盖

· 如果$R> \frac{n}{2} 且 L \leq \frac{n}{2}$ 则必定存在 $x\in [L,n/2] 或者 [n/2+1,R] 与 L+\frac{n}{2} 和 R -\frac{n}{2} 匹配$

s点为奇数时，只需根据叶子结点再接一个节点

## F.Fake Maxpooling

### 题解：

DP , 单调队列，优先队列，倍增ST表

for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!gcd[i][j]){
for(int k=1; k*i<=n&&k*j<=m;k++){
gcd[i*k][j*k] = k, A[k*i][k*j] = i*j*k;//lcm
}
}
}
}

int a[5005][5005];//a为处理出来的 lcm(i,j)
int que[5005];//维护下标
int b[5005][5005];
void func(){
long long sum = 0;
for(int i=1;i<=n;i++){
int l=1,r=1;
for(int j=1;j<=m;j++){
while(r>l && j-que[l] >= k) ++l;
while(r>l && a[i][j]>a[i][que[r-1]]) --r;
que[r++] = j;
if(j>=k) b[i][j-k+1] = a[i][que[l]];
}
}
//横向于纵向维护方式一样
for(int j=1;j<=m-k+1;j++){
int l=1,r=1;
for(int i=1;i<=n;i++){
while(r>l && i-que[l] >= k) ++l;
while(r>l && b[i][j]>b[que[r-1]][j]) --r;
que[r++] = i;
if(i>=k) sum += b[que[l]][j];
}
}
cout<<sum<<endl;
}

$maxv(i,j,k)=max\{maxv(i,j,k-1), maxv(i+1,j+1,k-1), maxv(i+1,j,k-1), maxv(i,j+1,k-1)\}$

$maxv(i,j,k)=max\{maxv(i,j,k), maxv(i+2^{(k-1)},j+2^{(k-1)},k-1),$

$maxv(i,j+2^{(k-1)},k-1), maxv(i+2^{(k-1)},j,k-1) \}$

void func(){
long long sum = 0;
int lok;
lok=floor(log2(k));
for(int l=0;l<=lok-1;l++){
for(int i=1;i+(1<<l)<=n;i++){
for(int j=1;j+(1<<l)<=m;j++){
a[i][j] = max(a[i][j], max(a[i+(1<<l)][j+(1<<l)], max(a[i+(1<<l)][j], a[i][j+(1<<l)])));//最后处理出来的大小为 2^lok
}
}
}

for(int i=1;i<=n-k+1;i++){
for(int j=1;j<=m-k+1;j++){
sum += max(a[i][j],max(a[i+k-(1<<lok)][j+k-(1<<lok)],max(a[i+k-(1<<lok)][j],a[i][j+k-(1<<lok)])));
}
}
cout<<sum<<endl;
}

## B.Boundary

### 题解：

$Ax^{2}+Ay^{2}+Bx+Cy+D=0$

$A=\begin{vmatrix} x_{1}& y_{1} & 1\\ x2& y2& 1\\ x3& y3& 1 \end{vmatrix}$
$=x_{1}(y2-y3)-y_{1}(x2-x3)+x2x3-x3x2$

$B=-\begin{vmatrix} x_{1}^{2}+y_{1}^{2}& y_{1} & 1\\ x_{2}^{2}+y_{2}^{2}& y_{2}& 1\\ x_{3}^{2}+y_{3}^{2}& y_{3}& 1 \end{vmatrix}$
$= (x_{1}^{2}+y_{1}^{2})(y_{3}-y_{2})+ (x_{2}^{2}+y_{2}^{2})(y_{1}-y_{3})+(x_{3}^{2}+y_{3}^{2})(y_{2}-y_{1})$

$C=\begin{vmatrix} x_{1}^{2}+y_{1}^{2}& x_{1} & 1\\ x_{2}^{2}+y_{2}^{2}& x_{2}& 1\\ x_{3}^{2}+y_{3}^{2}& x_{3}& 1 \end{vmatrix}$
$=(x_{1}^{2}+y_{1}^{2})(x_{2}-x_{3})+ (x_{2}^{2}+y_{2}^{2})(x_{3}-x_{1})+(x_{3}^{2}+y_{3}^{2})(x_{1}-x_{2})$

$D=-\begin{vmatrix} x_{1}^{2}+y_{1}^{2}& x_{1} & y_{1}\\ x_{2}^{2}+y_{2}^{2}& x_{2}& y_{2}\\ x_{3}^{2}+y_{3}^{2}& x_{3}& y_{3} \end{vmatrix}$
$=(x_{1}^{2}+y_{1}^{2})(x_{3}y_{2}-x_{2}y_{3})+ (x_{2}^{2}+y_{2}^{2})(x_{1}y_{3}-x_{3}y_{1})+(x_{3}^{2}+y_{3}^{2})(x_{2}y_{1}-x_{1}y_{2})$

$(x-(-\frac{B}{2A}))^2+(y-(-\frac{C}{2A})^2)=(\sqrt{\frac{B^{2}+C^{2}-4AD}{4A^{2}}})^{2}$

$x=-\frac{B}{2A} = \frac{(x_{1}^{2}+y_{1}^{2})(y_{3}-y_{2})+ (x_{2}^{2}+y_{2}^{2})(y_{1}-y_{3})+(x_{3}^{2}+y_{3}^{2})(y_{2}-y_{1})}{2\times(x_{1}(y2-y3)-y_{1}(x2-x3)+x2x3-x3x2)}$

$y=-\frac{C}{2A} = -\frac{(x_{1}^{2}+y_{1}^{2})(x_{2}-x_{3})+ (x_{2}^{2}+y_{2}^{2})(x_{3}-x_{1})+(x_{3}^{2}+y_{3}^{2})(x_{1}-x_{2})}{2\times(x_{1}(y2-y3)-y_{1}(x2-x3)+x2x3-x3x2)}$

$r=\sqrt{\frac{B^{2}+C^{2}-4AD}{4A^{2}}}$

Code:

const int maxn = 2e6+5;
struct Node{
double x,y;
}node[maxn];
int ans ;

map<pair<double,double>,int>mp;
//由于其中一个点为(0,0)

void solve(Node a,Node b){
double x = ((a.x*a.x+a.y*a.y)*(b.y)-(b.x*b.x+b.y*b.y)*(a.y))/(2.0*(a.x*b.y-a.y*b.x));
double y = ((a.x*a.x+a.y*a.y)*(b.x)-(b.x*b.x+b.y*b.y)*(a.x))/(2.0*(a.y*b.x-a.x*b.y));
mp[{x,y}]++;
ans=max(ans,mp[{x,y}]);
}

int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>node[i].x>>node[i].y;
}

for(int i=1;i<=n;i++){
mp.clear();
for(int j=i+1;j<=n;j++){
if(node[i].x*node[j].y==node[i].y*node[j].x) continue; //不能关于原点对称
solve(node[i],node[j]);
}
}
cout<<ans+1<<endl;
return 0;
}

## J.Just Shuffle

### 题解：

https://blog.csdn.net/qq_36102055/article/details/107456175

1.置换是可以分成块的：也就是(2,3,1)和(4,5)这两个块，你可以发现无论怎么置换都不会发生这两个集合的元素之间互换。
2.存在循环：也就是对于每个块，在置换一定次数之后就会变回原样，比如(2,3,1)这个块在置换三次后就会变回原来排列中的位置
3.每个环的(下面不叫块了叫环)循环的大小就是块的元素的数目

$C = lcm(r_1,r_2,..,r_n)$

$A^C = A$

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define pb push_back
#define eps 1e-8
#define endl '\n'
using namespace std;
const ll maxn = 1e6 + 5;
int n,k,a[maxn],ans[maxn];
bool vis[maxn];
vector<int> v;
void setinv(){
int r = v.size(),inv;//r为环的大小，inv为k在r下的逆元
for(int i = 0; i < r; i++)
if((ll) k * i % r == 1)inv = i;//求逆元
for(int i = 0; i < r; i++)
ans[v[i]] = v[(i + inv) % r];//转inv次
}
int main(){
scanf("%d %d",&n,&k);
for(int i = 1; i <= n; i++)
scanf("%d",a + i);
for(int i = 1; i <= n; i++){
if(!vis[i]){
v.clear();
int x = a[i];
while(!vis[x]){//找环操作
v.push_back(x);
vis[x] = 1;
x = a[x];
}
//找到环后就处理该环所有位置的值
setinv();
}
}
for(int i = 1; i <= n; i++)
printf("%d ",ans[i]);
return 0;
}

## A.All with Pairs

### 题解：

$O(n\times m)$利用map记录后缀出现次数​ + $O(n^2)$ 枚举两个点 x $O(m)$ 遍历前缀长度\计算总和

$O(n \times m)$ 求出后缀出现次数 , 再 $O(n \times m)$遍历n个字符串的前缀值，出现与后缀相同则相加。但是原题中要求求出最长匹配，所以要减去前面多加的长度。可以使用 next[] 数组

//给定n个字符串，求所有字符串最长的前缀与后缀相等长度的平方和。
//如样例，匹配长度为1,2,3的分别有4,4,1个，所以答案为
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn = 1e6+5;
const ull mod = 998244353;
string str[maxn];
int nex[maxn];
map<ull,ull>Hsh;
const ull base = 131;
void getNext(string s){
int i=0,j=-1;
nex[i] = j;
while(i<(int)s.length()){
if(j==-1 || (s[i] == s[j])){
i++,j++;
nex[i] = j;
}else j = nex[j];//向前匹配位置移动
}
}
void getHash(string s){
ull ans = 0;
ull bas = 1;
for(int i=s.length()-1;i>=0;i--){
ans = (s[i]*bas + ans);
bas *= base;
Hsh[ans]++;
}
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>str[i];
ull ans = 0;
for(int i=1;i<=n;i++) getHash(str[i]);
for(int i=1;i<=n;i++){
ull res = 0;
getNext(str[i]);
for(int j=0;j<(int)str[i].length();j++){
res = (res*base+str[i][j]);
// cout<<res<<" "<<Hsh[res]<<endl;
ans = (ans + Hsh[res] * (j+1) % mod *(j+1) %mod)%mod ;//个数
ans = (ans - Hsh[res] * nex[j+1] % mod *nex[j+1] % mod + mod)%mod;
ans = (ans%mod+mod)%mod;
}
}
cout<<ans<<endl;
return 0;
}

## G.Greater and Greater

### 题意：

$n,m (1≤n≤150000,1≤m≤min\{n,40000\}).$

$1\leq A_i,B_i\leq10^9$

### 思路：

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+100;
bitset<N>ans,f;
struct node{
int pos, x;
bool operator < (const node &A) const {
return x > A.x;
}
}a[N],b[N];
int n,m;
int main(){
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; ++i)
scanf("%d",&a[i].x), a[i].pos = i;
for (int i = 1; i <= m; ++i)
scanf("%d",&b[i].x), b[i].pos = i;
sort(a+1,a+n+1);
sort(b+1,b+m+1);
ans.set(); f.reset();

for (int i = 1, j = 0; i <= m; ++i){
while((j+1) <= n && a[j+1].x >= b[i].x){
f[a[j+1].pos] = 1;
j++;
}
ans &= (f >> b[i].pos);
}
printf("%d\n",(int)ans.count());
return 0;
}

## H.Happy Triangle

### 题意：

1.插入 $x$ 到 MS 中

2.删除 $x$ 在 MS 中

3.给出一个 $x$ , 是否能在 MS 中找到两个元素 a,b 使得与 $x$ 一起构成 nondegenerate triangle

（三点不共线的三角形）

### 思路：

posted @ 2020-07-30 21:15  Tianwell  阅读(171)  评论(0编辑  收藏  举报