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=2n−1 每一位的贡献实际是杨辉三角
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=n∑i=1n∑j=i+1n(ai−bj)2
然后把
(
a
i
−
b
j
)
2
(a_i-b_j)^2
(ai−bj)2拆开 变成
a
i
2
+
b
j
2
−
2
a
i
b
j
a_i^2+b_j^2-2a_ib_j
ai2+bj2−2aibj 维护一下
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=1n∑j=0i×9∑k=1totfi−1,j−numk
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;
}