2021.8.10 提高B组模拟赛

2021.8.10 2021.8.10 2021.8.10 模拟赛
目录:

T1.单峰
T2.祖孙询问
T3.比赛
T4.数字

T 1 : T1: T1单峰

在这里插入图片描述

分析:

随便找规律 a n s = 2 n − 1 ans=2^{n-1} ans=2n1 每一位的贡献实际是杨辉三角
l o n g long long l o n g   +   long~+~ long + 快速幂

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const ll Mod=1e9+7;
ll n;
ll ksm(ll a,ll k)
{
	ll res=1;
	while(k)
	{
		if(k&1) (res*=a)%=Mod;
		k>>=1;
		(a*=a)%=Mod;
	}
	return res%Mod;
}
int main(){
	scanf("%lld",&n);
	printf("%lld",ksm(2,n-1)%Mod);
	return 0;
} 

T 2 : T2: T2祖孙询问

在这里插入图片描述

分析:

s b L C A sbLCA sbLCA即可 l c a lca lca x x x就是 y y y的祖先 为 y y y就是 x x x的祖先

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=4e4+5;
int n,T,root,fa[N][22],dep[N],head[N],tot;
struct node{
	int to,next;
}a[N<<1];
void add(int x,int y)
{
	a[++tot]=(node){y,head[x]};
	head[x]=tot;
}
void dfs(int x,int father)
{
	fa[x][0]=father;
	dep[x]=dep[father]+1;
	for(int i=1;i<=20;i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int i=head[x];i;i=a[i].next)
	{
		int qwq=a[i].to;
		if(qwq==father) continue;
		dfs(qwq,x);
	}
}
int LCA(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=20;i>=0;i--)
		if(dep[fa[x][i]]>=dep[y])
			x=fa[x][i];
	if(x==y) return x;
	for(int i=20;i>=0;i--)
		if(fa[x][i]^fa[y][i])
		{
			x=fa[x][i];
			y=fa[y][i];
		}
	return fa[x][0];
}
int main(){
	scanf("%d",&n);
	for(int i=1,x,y;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
		if(y==-1) root=x;
		else add(x,y),add(y,x); 
	}
	dfs(root,0);
	scanf("%d",&T);
	while(T--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		int Lca=LCA(x,y),ans=0;
		if(Lca==x) ans=1;
		else if(Lca==y) ans=2;
		printf("%d\n",ans);
	}
	return 0;
}

T 3 : T3: T3比赛

在这里插入图片描述

分析:

O ( n 2 ) O(n^2) O(n2)暴力就是枚举两个人直接算
a n s = ∑ i = 1 n ∑ j = i + 1 n ( a i − b j ) 2 n ans=\frac{\sum_{i=1}^n\sum_{j=i+1}^n(a_i-b_j)^2}{n} ans=ni=1nj=i+1n(aibj)2
然后把 ( a i − b j ) 2 (a_i-b_j)^2 (aibj)2拆开 变成 a i 2 + b j 2 − 2 a i b j a_i^2+b_j^2-2a_ib_j ai2+bj22aibj 维护一下 a a a的前缀和 前缀平方和
二分查找 b j b_j bj的位置 然后随便判一判就行了

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=5e4+5;
ll n,a[N],sum[N][2],x;
long double res;
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)
	{
		sum[i][0]=sum[i-1][0]+a[i];
		sum[i][1]=sum[i-1][1]+a[i]*a[i];
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&x);
		if(x<=a[1]) res+=n*x*x+sum[n][1]-2ll*sum[n][0]*x;
		else if(x>=a[n]) res-=n*x*x+sum[n][1]-2ll*sum[n][0]*x;
		else
		{
			int p=lower_bound(a+1,a+n+1,x)-a;p--;
			res+=(n-p)*x*x+sum[n][1]-sum[p][1]-2ll*(sum[n][0]-sum[p][0])*x-(p*x*x+sum[p][1]-2ll*sum[p][0]*x);
		}
	}
	printf("%.1Lf",res*1.0/n);
	return 0;
}

T 4 : T4: T4数字

在这里插入图片描述

分析:

淦比赛时候看成有 2 n 2^n 2n个数位
f i , j f_{i,j} fi,j表示长度为 i i i 和为 j j j的方案数 f i , j = ∑ i = 1 n ∑ j = 0 i × 9 ∑ k = 1 t o t f i − 1 , j − n u m k f_{i,j}=\sum_{i=1}^n\sum_{j=0}^{i\times 9}\sum_{k=1}^{tot}f_{i-1,j-num_k} fi,j=i=1nj=0i×9k=1totfi1,jnumk t o t tot tot S S S的大小

1. 1. 1. n n n位与后 n n n位和相等 其实就是找两个和相等 长度为 n n n的序列 a n s + = ∑ i = 0 n × 9 f n , i × f n , i ans+=\sum_{i=0}^{n\times 9}f_{n,i}\times f_{n,i} ans+=i=0n×9fn,i×fn,i
2. 2. 2. 奇数位与偶数位和相等 与上面同理

但这样会有重复的 就要再减去既满足 1 1 1又满足 2 2 2的方案数

n n n位之和 = = = n n n位之和 奇数位之和 = = = 偶数位之和
所以前 n n n位 中奇数位和 = = = n n n位 中偶数位和 且 前 n n n位中偶数位和 = = = n n n位中奇数位和
把这些方案数同理统计 最后减去即可

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const int N=1005,Mod=999983;
int n,num[11],tot;
ll f[N][N*9],res,res2,res3;
char a[11];
int main(){
	scanf("%d%s",&n,a+1);
	int len=strlen(a+1);
	for(int i=1;i<=len;i++)
		num[++tot]=a[i]-'0';
	f[0][0]=1ll;
	for(register int i=1;i<=n;i++)
	for(register int j=0;j<=i*9;j++)
	for(register int k=1;k<=tot;k++)
		if(j>=num[k]) (f[i][j]+=f[i-1][j-num[k]])%=Mod;
	for(int i=0;i<=n*9;i++)
		(res+=f[n][i]*f[n][i])%=Mod;
	int k=(n|1)>>1,k2=n-k;
	for(int i=0;i<=k*9;i++)
		(res2+=f[k][i]*f[k][i])%=Mod;
	for(int i=0;i<=k2*9;i++)
		(res3+=f[k2][i]*f[k2][i])%=Mod;
	printf("%lld",(res<<1)%Mod-(res2*res3)%Mod);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值