HGOI11.1集训题解
题解
我觉得我剩下的日子已经不多了,这一份题解很有写的意义。
第一题——序列(sequence)
【题目描述】
- 小Z 有一个序列,定义f(x)为x 在十进制下的位数,特别地,求∑1≤i<j≤nf(ai+aj)\sum_{1\leq i <j\leq n}f(a_i+a_j)1≤i<j≤n∑f(ai+aj)
- 其中n≤106,ai≤108n\leq10^6,a_i\leq10^8n≤106,ai≤108
- 显然这个题目拿到手有点难考虑。
- 我们考虑对于f(ai+aj)f(a_i+a_j)f(ai+aj),只有当两个数相加进位的时候才会对答案做出+1的贡献,否则就是原来的位数。
- 那么将原有数列进行排序,对答案无影响。
- 对于单个的aia_iai,只有当iii之前的aja_jaj满足10k−ai≤aj(10k<ai≤10k−1)10^k-a_i\leq a_j(10^k<a_i\leq 10^{k-1})10k−ai≤aj(10k<ai≤10k−1)才能对答案做出f(ai)+1f(a_i)+1f(ai)+1的贡献,否则贡献为f(ai)f(a_i)f(ai)。
- 然后二分查找满足条件的aja_jaj的个数就可以了
- 注意数据,要开longlong,不然你连10410^4104的数据都过不了
#include <bits/stdc++.h>
#define LL long long
using namespace std;
void fff(){freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);
}
LL read(){LL x=0;char ch=getchar();while(ch<'0'||ch>'9') ch=getchar();while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();return x;
}
const int N=1000010;
LL n;
LL a[N];
int main(){// fff();n=read();for(int i=1;i<=n;i++) a[i]=read();sort(a+1,a+n+1);LL ans=0;LL t=10;for(int i=1;i<=n;i++){LL tt=a[i],siz=0;while(tt){siz++;tt/=10;}while(t-a[i]<=0) t*=10;LL temps=lower_bound(a+1,a+i,t-a[i])-a;ans+=(LL)(i-temps)*(siz+1);ans+=(LL)siz*(temps-1);}cout<<ans<<'\n';
}
第二题——锁(lock)
【题目描述】
- 给出n个人,m和n个人的权值值,给每一个人附上若干把钥匙使得满足,每把钥匙对应一把锁,每个钥匙可以发给多个人,每个人可以拿多把钥匙。
求满足下面条件的最少的锁的数目
- 任意权值和SSS满足S<mS<mS<m的人的集合都无法开启所有的锁。
- 任何权值和SSS满足S≤S\leqS≤的人的集合能够开启所有的锁。
- 这个题目真的不是很好打,最开始乱搞只拿了20分。看了题解才知道是集合数学建模,但大家都不会也没什么亏的。
- 考虑两个满足S<mS<mS<m的不同的集合,如果两个集合的权值恰好比mmm小,再加上一个不包含的最小值比mmm要大的情况下,不能同时缺同一把钥匙,简单证明就是
满足S1<m,m≤S1+min1S_1<m,m\leq S_1+min_1S1<m,m≤S1+min1S2<m,m≤S2+min2S_2<m,m\leq S_2+min_2S2<m,m≤S2+min2 - 那么m≤S1+S2m\leq S_1+S_2m≤S1+S2
- 但是两个集合的人还是缺一把钥匙,不满足条件2,假设就不能成立
- 那么就可以知道,答案的个数就是满足S<m,m≤S+minS<m,m\leq S+minS<m,m≤S+min的集合个数
- 那就暴力枚举集合就可以了。
- 如果所有人的权值和都比mmm小,那就只要1把锁,没有人有钥匙就可以了。
- 非常不错的一道题
#include <bits/stdc++.h>
#define LL long long
using namespace std;
void fff(){freopen("lock.in","r",stdin);freopen("lock.out","w",stdout);
}
LL read(){LL x=0;char ch=getchar();while(ch<'0'||ch>'9') ch=getchar();while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();return x;
}
const int N=40;
LL n,m;
LL a[N];
const LL INF=1e9;
int main(){// fff();LL sum,minn;n=read(),m=read();LL ans=0;for(int i=1;i<=n;i++) a[i]=read();for(int i=0;i<(1<<n);i++){sum=0;minn=INF;for(int j=1;j<=n;j++){if((i&(1<<(j-1)))!=0)sum+=a[j];else minn=min(minn,a[j]);}if(sum<m&&sum+minn>=m) ans++;}ans=max(ans,(LL)1);cout<<ans;
}
第三题——正方形(square)
【题目描述】
- 给出T(T≤106)T(T\leq 10^6)T(T≤106)个n(n≤107)n(n\leq 10^7)n(n≤107),求出∏i=1n∏j=1nlcm(i,j)i∗lcm(i,j)j\prod_{i=1}^{n}\prod_{j=1}^{n}{\frac{lcm(i,j)}{i}*\frac{lcm(i,j)}{j}}i=1∏nj=1∏nilcm(i,j)∗jlcm(i,j)
这个题目一看就知道不是很和谐了,数学题放到最后面都没什么人做出来orz。打打暴力好像还有40分。
题解里好像各种打法都有,50-75不等,反演,欧拉函数等等,都可以进行优化,此处不赘述
正解:
先将式子化简∏i=1n∏j=1nlcm(i,j)i∗lcm(i,j)j=∏i=1n∏j=1ni∗jgcd(i,j)i∗i∗jgcd(i,j)j\prod_{i=1}^{n}\prod_{j=1}^{n}{\frac{lcm(i,j)}{i}*\frac{lcm(i,j)}{j}}=\prod_{i=1}^{n}\prod_{j=1}^{n}{\frac{\frac{i*j}{gcd(i,j)}}{i}*\frac{\frac{i*j}{gcd(i,j)}}{j}}i=1∏nj=1∏nilcm(i,j)∗jlcm(i,j)=i=1∏nj=1∏nigcd(i,j)i∗j∗jgcd(i,j)i∗j
=∏i=1n∏j=1ni∗jgcd(i,j)2=\prod_{i=1}^{n}\prod_{j=1}^{n}{\frac{i*j}{gcd(i,j)^2}}=i=1∏nj=1∏ngcd(i,j)2i∗j考虑对于每一个i,ji,ji,j是相互等价的,那么可以减少运算次数,变成:
(∏i=1n∏j=1ii∗jgcd(i,j))2(\prod_{i=1}^{n}\prod_{j=1}^{i}\frac{i*j}{gcd(i,j)})^2(i=1∏nj=1∏igcd(i,j)i∗j)2由于上下可以相互分离不影响,那么就可以改写成:
∏i=1n∏j=1ni∗j∏i=1n∏j=1ngcd(i,j)2\frac{\prod_{i=1}^{n}\prod_{j=1}^{n}i*j}{\prod_{i=1}^{n}\prod_{j=1}^{n}gcd(i,j)^2}∏i=1n∏j=1ngcd(i,j)2∏i=1n∏j=1ni∗j我们发现对于上面的分子来说,可以写成
∏i=1nin∗n!=(n!)2n\prod_{i=1}^{n}i^n*n!=(n!)^{2n}i=1∏nin∗n!=(n!)2n这一部分可以O(n)O(n)O(n)前缀积处理。
我们考虑分母∏i=1n∏j=1ngcd(i,j)2\prod_{i=1}^{n}\prod_{j=1}^{n}gcd(i,j)^2i=1∏nj=1∏ngcd(i,j)2
题解上面就一句“我们单独考虑每个素数对答案的贡献,对于一个素数x,它在kx处会对答案有(2k-1)的贡献,求一遍前缀积即为答案”,但这对于读者来说过于草率,非常难以理解。在此进行展开
考虑素数筛出每一个质数,对于每一个nnn的质因子pip_ipi,nnn之前每pip_ipi个数当中就会有一个数与nnn的gcdgcdgcd是pip_ipi,那么可以通过倍数法求出这些数的乘积,而对于与nnn的gcdgcdgcd是pi2,pi3p_i^2,p_i^3pi2,pi3等等的,由于之前已经筛过了pip_ipi的倍数,之后只要叠加再筛pip_ipi就可以了。代码实现较为难理解。
if(!visited[i]){//如果i是质数LL t=i;//t是质数for(int k=1;t<=T;k++,t*=i){//此处设T是最大值N,t逐渐变成p1^2,p1^3...for(LL tmp=t,num=i;tmp<=T;tmp+=t,num=1ll*num*i%MOD*i%MOD)//由于产生的gcd(i,i)等价,所以只筛一次//从前往后寻找sum[tmp]=1ll*sum[tmp]*num%MOD;//类乘}for(int k=i;k<=T;k+=i) visited[k]=true;//素数筛}
然后这一部分处理好之后就可以前缀积求出分母了。
然后暴力快速幂求出分子和分母的逆元(存在取模)。
#pragma GCC optimize(2)
#pragma G++ optimize(2)
#include <bits/stdc++.h>
#define LL long long
using namespace std;
void fff(){freopen("square.in","r",stdin);freopen("square.out","w",stdout);
}
int read(){int x=0;char ch=getchar();while(ch<'0'||ch>'9') ch=getchar();while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();return x;
}
const int MOD=19260817;
const int N=1e7+10;
const int T=1e7;
int n;
int prime[N],cnt;
LL sum[N],mul[N];
LL f[N];
int maxx=0;
bool visited[N];
LL power(int x,int y){int i=x;x=1;while(y>0){if(y%2==1)x=1ll*x*i%MOD;i=1ll*i*i%MOD;y/=2;}return x;
}
int main(){// fff();for(int i=0;i<=T;i++) sum[i]=1;for(int i=2;i<=T;i++){if(!visited[i]){LL t=i;for(int k=1;t<=T;k++,t*=i){for(LL tmp=t,num=i;tmp<=T;tmp+=t,num=1ll*num*i%MOD*i%MOD)sum[tmp]=1ll*sum[tmp]*num%MOD;}for(int k=i;k<=T;k+=i) visited[k]=true;}}for(int i=1;i<=T;i++) sum[i]=1ll*sum[i-1]*sum[i]%MOD;for(int i=1;i<=T;i++) sum[i]=sum[i]*sum[i]%MOD;mul[0]=1;for(int i=1;i<=T;i++)mul[i]=1ll*mul[i-1]*i%MOD;int t;t=read();while(t--){n=read();int ans=1ll*power(mul[n],2*n)*power(sum[n],MOD-2)%MOD;printf("%d\n",ans);}
}
HGOI11.1集训题解相关推荐
- 23春-第三次集训题解
23春-第三次集训题解 L1-1 植树问题 某学校植树节开展植树活动,已知树苗有m株,参加植树的同学有n人(且m>n),请问每位同学平均可以植树几株?还有几株剩余? 输入格式: 输入两个整数m和 ...
- 2017国庆 雅礼集训 题解合集
D1 D1 T1:Clique: 我做的题太少啦,这都没看出来.首先,这个式子是 c[i]−c[j]>=dis(i,j) c[i]-c[j] >= dis(i,j),即在数轴上这样的圆,如 ...
- 【某集训题解】【DAY 2 T3】与非
题目描述 作为一名新世纪共产主义的接班人,你认识到了资本主义的软弱性与妥协性,决定全面根除资本主义,跑步迈入共产主义.但是当你即将跨入共产主义大门的时候,遇到了万恶的资本家留下的与非电路封印,经过千辛 ...
- HGOI8.23集训题解
题解 今天是信心赛吗? 第一题--方程式(equation) [题目描述] 给出n次方程的系数,求出所有根(重根也要输出). n≤7n≤7n\leq 7,根的大小1≤x≤201≤x≤201\leq x ...
- 2018第一次校队集训题解
问题 A: 豆豆强的蛋糕店 时间限制: 1 Sec 内存限制: 128 MB 提交: 29 解决: 3 [提交] [状态] [讨论版] [命题人:外部导入] [Edit] [TestData] 题 ...
- 2019 SUST暑期集训题解(计算几何(二))
A . 梦想成为天文学家 这道题是一个原题,我们要用向量的知识来解决它,求解的就是四点共面. //四个点三个向量 构成一个行列式 行列式的结果为0则共面否则不共面 #include<iostre ...
- SUST 2019暑期集训题解(差分约束+生成树+传递闭包)
A 这个不等式组很眼熟吧 这道题的话上课讲过就是根据不等式建图然后跑一下最短路就可以了. #include<iostream> #include<cstring> #inclu ...
- 2019 SUST暑期集训题解(计算几何(平面几何))
A 来,求个三角形面积玩玩. 利用叉乘的特性就直接得到三角形的面积,如果三点共线则三点不构成三角形.此时叉乘结果为0. #include<iostream> #include<cst ...
- SUST暑期集训题解(可持久化数据结构)
A 可持久化线段树 #include<iostream> #include<cstdio> #include<cstring> #include<algori ...
最新文章
- OpenGL GLFW
- linux网络编程 华清,Linux网络编程之套接字
- 使用Ajax以一种形式上传数据和文件吗?
- 机器学习--支持向量机实战(四)核函数实现
- 迫切想要成功之后的喜悦感,失败太久有点心灵上小小的打击,还需要继续前进。...
- vue登录页面ajax,springboot+vue 登录页面(三)
- 大话数据结构 - 串
- IOS应用程序ipa安装包更换图标iocn、IOS应用分发一条龙
- 模拟京东快递单号查询案例
- python打开读取文件内容
- php必应壁纸 分辨率,Python爬取必应壁纸的代码实例
- 网络对抗技术 实验四
- 入门须知:次世代3D建模软件有哪些?
- 成都农商银行软件测试面试题,农商行历年笔试真题找不到?不慌!16家农商行笔试题库等你来刷!...
- 利用燕尾花数据集画出P-R曲线
- c# WPF 动态设置button的IsEnabled属性
- linux磁盘分区什么意思,linux 磁盘分区详解
- 小爱同学自定义100个音效
- MySQL创建索引-阿里云开发者社区
- 前端用node及forever部署