【学习笔记】2021.10.5 - 清北学堂模拟赛

T1 一

正解

暴力。

超级加倍版(n提升至1e5)

预处理 1~n 的逆元,然后

 

(以上为赛时手推出来的屑QWQ)

竖着求一遍,得到每个数的贡献。

然后就会发现一个垃圾规律:从1~\(\frac{n}{2}\),每一行的值在有规律地增加,根据这个规律直接计算每个数的贡献倍数即可。

代码

蒟蒻的屑代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
typedef long long ll;
const ll MO(1000000007);
ll n,num[1233],sum[1233],ans;
inline ll R(){
	ll x=0,f=1;char c='c';
	while(c>'9'||c<'0'){f=(c=='-')?-1:1;c=getchar();}
	while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
	return x*f;
}
inline ll fpow(ll x,ll y){
	ll res=1;
	while(y){
		if(y&1) res=(res*x)%MO;
		x=(x*x)%MO;
		y>>=1; 
	}
	return res;
}
inline ll FENSHU(ll fz,ll fm){return fz*fpow(fm,MO-2)%MO;}
inline ll ges(ll l,ll r){
	ll res=0;
	for(register int i=l;i<=r;++i) res=(res+FENSHU(1,i))%MO;
	res=(res+sum[l-1])%MO;
	return res;
}
int main(){
	n=R();
	for(register int i=1;i<=n;++i) num[i]=R();
	for(register int i=1,j=n;i<=j;i++,j--) sum[i]=sum[j]=ges(i,j);
	for(register int i=1;i<=n;++i) ans=(ans+sum[i]*num[i]%MO)%MO;	
	printf("%lld\n",ans);
	return 0;
}
/*
a   b   c   d   e
1/1 1/1 1/1 1/1 1/1
1/2 2/2 2/2 2/2 1/2
1/3 2/3 3/3 2/3 1/3
1/4 2/4 2/4 2/4 1/4
1/5 1/5 1/5 1/5 1/5

a   b   c   d   e   f
1/1 1/1 1/1 1/1 1/1 1/1
1/2 2/2 2/2 2/2 2/2 1/2
1/3 2/3 3/3 3/3 2/3 1/3
1/4 2/4 3/4 3/4 2/4 1/4
1/5 2/5 2/5 2/5 2/5 1/5
1/6 1/6 1/6 1/6 1/6 1/6
*/

T2

正解

使用1、2、10构造即可,先找到最大的小于等于m的等差数列的某一项,再将其中的若干位修改为1,使其与10形成回文数字。

不难证明,这若干个2的个数一定大于等于仍缺少的数对,设有x个2,则如果不足以填满,说明剩下的个数要比\(\frac{x \left( x+1 \right)}{2}\)要大,因此找到的最大的这一项不会是此项,与已知条件矛盾。

剩下的空余部分填充1145即可(数字多臭是不影响答案的)。

代码

更屑的代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int T,n,m,num[2333];
long long res,qwq;
int main(){
	scanf("%d",&T);
	for(register int i=2;i<=1010;++i) num[i]=num[i-1]+i-1;
	while(T--){
		scanf("%d%d",&n,&m);res=qwq=0;
		for(register int i=1;;++i) if((num[i]<=m)&&(num[i+1]>m)){qwq=m-num[i];res=i;break;}
		res=res-qwq;
		for(register int i=1;i<=qwq;++i) printf("1 ");
		for(register int i=1;i<=res;++i) printf("2 ");
		n-=qwq;n-=res;
		if(n){printf("10 ");n--;}
		for(register int i=1;i<=n;++i){printf("1145 ");}
		printf("\n");
	}
	return 0;
}

T3

正解

因为只需要记最大数值,所以考虑从大到小把点加入。

对于这个点连接的若干连通块,显然这些连通块合并以后,长度为1~直径的所有值都会被这个点作贡献。

但是怎么求连通块的直径呢?

实际上,合并连通块时,直径一定会出现在构成两个连通块的直径的四个点的任意组合中,所以跑4遍倍增LCA,即可求得直径。

代码

莫得。/kk

T4

Subtask1 - 40 pts

暴力。

可惜时间不够没有写TAT

Subtask2 - 10 pts(a=b=c=0)

只有一个d,所以输出 \(2^n\) 即可(所有子集)

Subtask3 - 20 pts(a=b=0)

对于每条边,显然如果该边想贡献答案,则两个端点都必须选上,剩余方案为 \(2^{n-2}\) ,所以将每条边乘上 \(2^{n-2}\) ,再加上 \(2^n \times d\) 即可。

Subtask4 - 20 pts(a=0)

平方项本质上就是从原图中选两条边的方案数。

但是,不要大e,这两条边可能是一条边!

当两条边为同一条边时

答案为\(m \times \ 2^{n-2}\),因为对于每一条边,都可以转化为上一个Subtask处理。

当两条边不为同一条边时

当两条边完全独立时

答案为\(\sum\limits_{v=1}^n{d[v](d[v]-1) \times 2^{n-3}}\),其中d[v]表示v点的度,此指对于每个点选择两条边的方案数,后面2的次幂表示定死三个点,剩下的随便选的方案数。

当有一个公共端点时

总方案除去以上两种情况的方案数(不含2的某次幂)再乘\(2^{n-4}\)得到最终方案。

正解

要用到数三元环,可惜我不会QWQ

代码

还是莫得QWQ。

zhxの合理の难度评价

T1 = <T1

T2 = Strange T2

T3 = T3

T4 = T4

看来我果然是大ZZ,什么也不会QWQ

没救了TAT

posted @ 2021-10-05 14:37  Binaries  阅读(59)  评论(2编辑  收藏  举报
浏览器标题切换
浏览器标题切换end