传送门:CF
前提提要:无
A题:A. Twin Permutations
简单思维题.不难发现只要将所有数对 a i + b i ai+bi ai+bi控制等于 n n n即可.因为两个数列都是排列,所以这个是必可以满足的.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];
int main() {
	int T=read();
	while(T--) {
		int n=read();
		for(int i=1;i<=n;i++) a[i]=read();
		for(int i=1;i<=n;i++) {
			cout<<n-a[i]+1<<" ";
		}
		cout<<endl;
	}
	return 0;
}
 
B题:B. Array merging
简单思维题.因为我们可以掌控出数的时刻.不难发现,我们只要找到两个数列中每一个数字的连续的个数即可.我们最终的答案就是两个数列中最大的每一个数字的连续个数和.
 举一个栗子,对于合并,假设我们最终的答案是 
     
      
       
       
         1 
        
       
      
        1 
       
      
    1,我们肯定是需要找到a数列中最长的连续的1的位置(记为pos1)以及b数列中最长的连续的1的位置(记为pos2),我们先将pos2,pos1之前的所有数字都加入c中,然后我们再加入所有的1即可.
 注意,在一个数列中假设数字不是连续的,我们必然是不可能让它们在合并后的数列中是连续的.这个很显然,就不在赘述了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn],b[maxn];
int main() {
	int T=read();
	while(T--) {
		int n=read();
		map<int,int>num1,num2;
		for(int i=1;i<=n;i++) {
			a[i]=read();
		}
		for(int i=1;i<=n;i++) {
			b[i]=read();
		}
		int cnt=1;num1[a[1]]=1;
		for(int i=2;i<=n;i++) {
			if(a[i]==a[i-1]) {
				cnt++;	
			}
			else {
				num1[a[i-1]]=max(num1[a[i-1]],cnt);
				cnt=1;
			}
			if(i==n) {
				num1[a[i]]=max(num1[a[i]],cnt);
			}
		}
		cnt=1;num2[b[1]]=1;
		for(int i=2;i<=n;i++) {
			if(b[i]==b[i-1]) {
				cnt++;
			}
			else {
				num2[b[i-1]]=max(num2[b[i-1]],cnt);
				cnt=1;
			}
			if(i==n) {
				num2[b[i]]=max(num2[b[i]],cnt);
			}
		}
		int maxx=-int_INF;
		for(int i=1;i<=2*n;i++) {
			maxx=max(maxx,num1[i]+num2[i]);
		}
		cout<<maxx<<endl;
	}
	return 0;
}
 
C题:C. Copil Copac Draws Trees
一道图论题.推一推样例之后很容易知道应该怎么做.
 考虑对所有给定的边进行建树,并且记录每一条边的优先级.
 然后我们就可以开始从根节点开始跑dfs,对于每一条边,假设我们的下一条边的优先级小于我们的当前边,我们就可以在一次循环中将其遍历,反之我们需要将花费+1.
 但是需要注意的是,我们在一次循环中可能遇到很多条需要加花费的边,这些边的花费是可以在一次循环中解决的,也就是花费只需要一,所以我们不能反复累加.
 解决方案是,可以记录遍历到每一个节点需要的花费,最后在每一个叶子结点取一个 
     
      
       
       
         m 
        
       
         a 
        
       
         x 
        
       
      
        max 
       
      
    max.
 图论题不是很好用文字来讲明白,建议结合代码食用
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
map<int,map<int,int> >mp;
vector<int>tree[maxn];
int vis[maxn];int ans=0;
void dfs(int u,int per_u,int last,int dep) {
	for(int i=0;i<tree[u].size();i++) {
		int v=tree[u][i];
		if(v==per_u) continue;
		if(mp[u][v]>last) {
			dfs(v,u,mp[u][v],dep);
		}
		else {
			dfs(v,u,mp[u][v],dep+1);
		}
	}
	ans=max(ans,dep);
}
int main() {
	int T=read();
	while(T--) {
		int n=read();
		for(int i=1;i<=n;i++) {
			tree[i].clear();
			vis[i]=0;
		}
		mp.clear();
		for(int i=1;i<=n-1;i++) {
			int u=read(),v=read();
			tree[u].push_back(v);
			tree[v].push_back(u);
			mp[u][v]=mp[v][u]=i;
		}
		ans=1;
		dfs(1,0,0,1);
		cout<<ans<<endl;
	}
	return 0;
}
 
D题:D. The BOSS Can Count Pairs
本题的突破口也是比较经典的了.对于这种看起来很像 n 2 n^2 n2的题目,一般都有一些性质.比如本题,在数的值域方面就是一个突破口.很显然对于n^2的暴力算法,我们的值域可以达到1e9,但是为什么这里的值域才n呢,想到这里,对于这道题应该就有思路了.
对于 
     
      
       
       
         a 
        
       
         i 
        
       
         + 
        
       
         a 
        
       
         j 
        
       
         = 
        
       
         b 
        
       
         i 
        
       
         + 
        
       
         b 
        
       
         j 
        
       
      
        ai+aj=bi+bj 
       
      
    ai+aj=bi+bj,又因为 
     
      
       
       
         b 
        
       
         i 
        
       
         + 
        
       
         b 
        
       
         j 
        
       
         < 
        
       
         = 
        
       
         2 
        
       
         ∗ 
        
       
         n 
        
       
      
        bi+bj<=2*n 
       
      
    bi+bj<=2∗n,所以有 
     
      
       
       
         a 
        
       
         i 
        
       
         ∗ 
        
       
         a 
        
       
         j 
        
       
         < 
        
       
         = 
        
       
         2 
        
       
         ∗ 
        
       
         n 
        
       
      
        ai*aj<=2*n 
       
      
    ai∗aj<=2∗n,因为最终是求点对的数量,和先后顺序无关,所以我们不妨将a数组从小到大排一个序.此时我们保证 
     
      
       
       
         a 
        
       
         i 
        
       
         < 
        
       
         = 
        
       
         a 
        
       
         j 
        
       
      
        ai<=aj 
       
      
    ai<=aj.
 然后我们枚举 
     
      
       
       
         a 
        
       
         j 
        
       
      
        aj 
       
      
    aj,注意此时我们不能枚举 
     
      
       
       
         a 
        
       
         i 
        
       
      
        ai 
       
      
    ai,这样我们的复杂度还是炸裂的(此时为 
      
       
        
        
          a 
         
        
          i 
         
        
       
         ai 
        
       
     ai~ 
      
       
        
        
          2 
         
        
          ∗ 
         
        
          n 
         
        
          / 
         
        
          a 
         
        
          [ 
         
        
          i 
         
        
          ] 
         
        
       
         2*n/a[i] 
        
       
     2∗n/a[i]),至于为什么枚举 
     
      
       
       
         a 
        
       
         j 
        
       
      
        aj 
       
      
    aj竟然就可以缩小复杂度呢,这就是算法的巧妙所在了.真是太妙啦.
考虑枚举 a j aj aj,然后我们此时可以枚举 a i ai ai的值域,显然我们的 a i < = 2 ∗ n ai<=\sqrt{2*n} ai<=2∗n,因为此时 a i < = a j ai<=aj ai<=aj.此时我们就可以将复杂度降为 n n n\sqrt{n} nn了.因为此时枚举了 a j aj aj,所以我们也知道了 b j bj bj,所以我们就知道了与 a i ai ai相配的 b i bi bi的大小,也就是 a i ∗ a j − b j ai*aj-bj ai∗aj−bj.所以此时我们的问题就变成了有多少个 < a i , b i > <ai,bi> <ai,bi>满足这个关系.这个也不难解决,使用一个桶记录一下即可.
注意本题比较卡内存和时限,map会被卡,数组大小需要计算一下,还需要开longlong
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
int mp[635][200010];
#define int long long
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
struct Node{
	int a,b;
	bool operator < (const Node &rhs) const {
		return a<rhs.a;
	}
}node[200010];
int mp1[200010],mp2[200010];
signed main() {
	int T=read();
	while(T--) {
		int n=read();
		for(int i=1;i<=n;i++) {
			node[i].a=read();
			mp1[node[i].a]++;
		}
		for(int i=1;i<=n;i++) {
			node[i].b=read();
			mp2[node[i].b]++;
		}
		sort(node+1,node+n+1);
		int ans=0;
		int limit=__builtin_sqrt(2*n);
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=limit&&j*node[i].a<=2*n;j++) {
				if(mp1[j]) {
					if(node[i].a*j-node[i].b>n||node[i].a*j-node[i].b<0) continue;
					ans+=(ll)mp[j][node[i].a*j-node[i].b];
				}
			}
			if(node[i].a<=limit)
				mp[node[i].a][node[i].b]++;
		}
		for(int i=1;i<=n;i++) {
			if(node[i].a<=limit)
				mp[node[i].a][node[i].b]=0;
			mp1[node[i].a]=0;mp2[node[i].b]=0;
		}
		cout<<ans<<endl;
	}
	return 0;
}









