HGOI 20190711 题解
Problem A 矩阵第K小数
给定一个$n \times m$的矩阵,位置$A_{i,j} = i\times j$,
给出$Q$个询问,每一次查询矩阵中第$Q_i$小的数是多少。
对于100%的数据 , $1 \leq n,m \leq 10^9 , Q \leq 100 , 1 \leq Q_i \leq n\times m$
Sol : 本题采用暴力模拟的复杂度是不能通过的,并且其矩阵的排布都是有规律的。
第$i$行构成的数列是公差为$i$的等差数列。 可以考虑枚举每一行,然后就可以O(1) 计算这一行有多少比某一数$x$小了。
同时,对于每一个询问二分答案,然后可以扫一遍$n$然后二分计算每一行的贡献。这样的复杂度就是$O(Qnlog_{2} (nm) )$
同时考虑,每一行贡献是类似于$\lfloor \frac{x}{i} \rfloor$的东西,我们会发现这个东西对于$i$递增,它可能的取值只会有$\sqrt{x}$种。
并且其值是单调下降的。 所以我们可以$O(\sqrt{n})$每次遍历每一个"平台"。但是由于需要二分答案,这样的复杂度会变成$log_2 n \sqrt{n}$
总时间复杂度会变成$O(Q\sqrt{n} log_{2} (nm) log_2 n)$无法通过。
如何在$O(\sqrt{n})$的复杂度遍历每一个块,然后统一计算是本题的瓶颈。
问题等价于求$\sum\limits_{i=1}^n \lfloor \frac{x}{i} \rfloor $,我们可以考虑一个$i$满足$a = \lfloor \frac{x}{i} \rfloor $
在某一个区间内,有$a \leq \lfloor \frac{x}{i} \rfloor < a+1 $ ,所以可以解得此时的$i \in [\left \lfloor \frac{x}{\left \lfloor \frac{x}{i} \right \rfloor+1} \right \rfloor + 1, \left \lfloor \frac{x}{\left \lfloor \frac{x}{i} \right \rfloor} \right \rfloor]$
所以最后的复杂度就可以做到$O(Qlog_2 (nm) \sqrt{n} )$ 了。
# pragma GCC optimize()
# include <bits/stdc++.h>
# define int long long
using namespace std;
int n,m,q;
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
int calc(int i,int x){
if (x%i==) return min(x/i-,m);
else return min(x/i,m);
}
bool check(int x,int k)
{
int ret=;
for (int l=,r;l<=min(x,m);l=r+) {
r=x/(x/l);
ret+=min((x/l),n)*(r-l+);
}
return (ret>=k);
}
signed main()
{
n=read();m=read();q=read();
while (q--) {
int x=read();
int l=,r=n,ans;
while (l<=r) {
int mid=(l+r)>>;
if (check(mid,x)) ans=mid,r=mid-;
else l=mid+;
}
printf("%lld\n",ans);
}
return ;
}
mat.cpp
Problem B 最小极差生成树
给出$n$个点$m$条边的连通图$G=(V,E)$,求出一棵生成树使得其最大边权和最小边权的差最小。
对于100%的数据$1 \leq m\leq 4000 , 1 \leq n \leq 1000$
Sol : 枚举每一条边,以这条边权$s$为下界跑最小生成树,找出最小生成树的最大边权为$d$.
用$d-s$更新答案。注意可能会有不合法情况,输出-1即可。
# pragma GCC optimize()
# include <bits/stdc++.h>
using namespace std;
const int N=4e3+;
int n,m,f[N];
struct node{ int u,v,w;}E[N];
bool cmp(node a,node b) {return a.w<b.w;}
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
int father(int x) {
if (f[x]==x) return x;
return f[x]=father(f[x]);
}
int MST(int W)
{
for (int i=;i<=n;i++) f[i]=i;
int tmp=,o=;
for (int i=;i<=m;i++) {
if (E[i].w<W) continue;
int fx=father(E[i].u),fy=father(E[i].v);
if (fx==fy) continue;
tmp++; f[fx]=fy; o=max(o,E[i].w);
if (tmp==n-) break;
}
if (tmp!=n-) return -;
else return o;
}
int main()
{
int T=read();
while (T--) {
n=read();m=read();
for (int i=;i<=m;i++) {
int u=read(),v=read(),w=read();
E[i]=(node){u,v,w};
}
sort(E+,E++m,cmp);
int ans=-;
for (int i=;i<=m;i++) {
int t=MST(E[i].w);
if (t==-) continue;
if (ans==-) ans=t-E[i].w;
else ans=min(ans,t-E[i].w);
}
printf("%d\n",ans);
}
return ;
}
min.cpp
Problem C 数字分组
个体互异而值可能相同$n$个数$a_i$划分为若干组。 对于某一组记下这组元素的极差(最大数-最小数)
一种合法的划分要求每一组元素极差的和有$\leq M$的限制。求出所有合法划分的总数$mod \ 10^9 + 7$的值。
对于20%的数据 ,$1 \leq n \leq 10$ ; 对于另外20%的数据,$M=0$
对于100%的数据,$1 \leq n \leq 200,0 \leq M \leq 1000,1 \leq a_i \leq 500 $
Sol : 对于20%数据直接第二类斯特林数求和然后乘起来即可。
对于100%的数据考虑DP。
先对数据排序,记$f_{i,j,k}$表示前$i$个数,还有$j$个划分集可以添加元素,当前差值和为$k$方案总数。
首先,显然即将添加的数$a_i$一定比之前添加的所有数要大,所以对于每一个没有完全划分好的集合都有贡献。首先计算当前差值的和是多少,我们会向每一个没有划分好的集合中添加一个差值$a_i - a_{i-1}$ , 所以当前差值的和就是$k + (a_i - a_{i-1})\times j$.
这是因为每一组的最值差就是这一组当中最大值和最小值之间所有数的差的和 。
所以这$j$组由于没有被划分好,就需要向里面添加这个差值$a_i - a_{i-1}$
考虑新添加这个元素作为一个新的分组的开始:$f_{i,j+1,v} += f_{i-1,j,k}$
考虑新添加的这个元素作为一个新的分组的开始和结束:$f_{i,j,v} += f_{i-1,j,k}$
考虑新添加的元素作为之前一个旧的还没划分好的组的非结束的元素:$f_{i,j,v} += f_{i-1,j,k}\times j$ ($j \neq 0 $)
考虑新添加的元素作为之前一个旧的还没划分好的组的结束元素$f_{i,j-1,v} += f_{i-1,j,k}\times j$ ($j \neq 0 $)
注意到这里枚举的状态$k$表示的是由那一维状态转移过来的状态$k$
用滚动数组实现就可以排除空间限制。
复杂度$O(n^2k)$
# pragma GCC optimize()
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int mo=1e9+;
int f[][][];
int a[];
int n,w;
signed main()
{
scanf("%lld%lld",&n,&w);
for (int i=;i<=n;i++) scanf("%lld",&a[i]);
sort(a+,a++n);
int p=; f[p][][]=;
for (int i=;i<=n;i++) {
p^=; memset(f[p],,sizeof(f[p]));
for (int j=;j<=i;j++)
for (int k=;k<=w;k++) {
int v=(a[i]-a[i-])*j+k;
if (v>w) continue;
f[p][j+][v]+=f[p^][j][k]; f[p][j+][v]%=mo;
f[p][j][v]+=f[p^][j][k];f[p][j][v]%=mo;
if (j) {
f[p][j][v]+=f[p^][j][k]*j; f[p][j][v]%=mo;
f[p][j-][v]+=f[p^][j][k]*j;f[p][j-][v]%=mo;
}
}
}
int ret=;
for (int k=;k<=w;k++)
ret+=f[p][][k],ret%=mo;
printf("%lld\n",ret);
return ;
}
grp.cpp
HGOI 20190711 题解的更多相关文章
- HGOI 20181028 题解
HGOI 20181028(复赛备考) /* 真是暴力的一天,最后一题MLE?由于数组开得太大了!!! 270滚粗 考场上好像智商高了很多?!(假的) */ sol:暴力求解,然后没有数据范围吐槽一下 ...
- HGOI 20190310 题解
/* 又是又双叒叕WA的一天... 我太弱鸡了... 今天上午打了4道CF */ Problem 1 meaning 给出q组询问,求下列函数的值$ f(a) = \max\limits_{0 < ...
- HGOI 20190303 题解
/* 记一串数字真难. 5435 今天比赛又是hjcAK的一天. 今天开题顺序是312,在搞T1之前搞了T3 昨天某谷月赛真是毒瘤. 但是讲评的同学不错,起码T4看懂了... 构造最优状态然后DP的思 ...
- HGOI 20180224 题解
/* The Most Important Things: ljc chat with fyh on QQTa说期末考Ta数学74分感觉不好但是我觉得fyh是地表最强的鸭~~(of course en ...
- HGOI 20190218 题解
/* 又是AK局... hjc又双叒叕AK了... Hmmm...我侥幸 */ Problem A card 给出无序序列a[]可以选择一个数插入到合适的位置作为一次操作,至少多少次操作后可以把序列变 ...
- HGOI 20190217 题解
/* for me,开训第一天 /beacuse 文化课太差被抓去补文化课了... 看一眼题 : AK局? 但是,Wa on test #10 in problem C 290! (就差那么一咪咪) ...
- HGOI 20181103 题解
problem:把一个可重集分成两个互异的不为空集合,两个集合里面的数相乘的gcd为1(将集合中所有元素的质因数没有交集) solution:显然本题并不是那么容易啊!考场上想了好久.. 其实转化为上 ...
- HGOI 20181101题解
/* 又是爆0的一天(不知道今年高考难不难,反正今天(信息学)真的难!) */ solution:对于两个数相加,有一个显然的结论就是要么不进位(相对于位数大的),要么(进最多一位) 然后对于整个数组 ...
- HGOI 20191108 题解
Problem A 新婚快乐 一条路,被$n$个红绿灯划分成$n+1$段,从前到后一次给出每一段的长度$l_i$,每走$1$的长度需要$1$分钟. 一开始所有红绿灯都是绿色的,$g$分钟后所有红绿灯变 ...
随机推荐
- # [爬虫Demo] pyquery+csv爬取猫眼电影top100
目录 [爬虫Demo] pyquery+csv爬取猫眼电影top100 站点分析 代码君 [爬虫Demo] pyquery+csv爬取猫眼电影top100 站点分析 https://maoyan.co ...
- CSP 命令行选项(201403-3)
问题描述 请你写一个命令行分析程序,用以分析给定的命令行里包含哪些选项.每个命令行由若干个字符串组成,它们之间恰好由一个空格分隔.这些字符串中的第一个为该命令行工具的名字,由小写字母组成,你的程序不用 ...
- spark教程(11)-sparkSQL 数据抽象
数据抽象 sparkSQL 的数据抽象是 DataFrame,df 相当于表格,它的每一行是一条信息,形成了一个 Row Row 它是 sparkSQL 的一个抽象,用于表示一行数据,从表现形式上看, ...
- C++ 友元(friend关键字)、类中的重载、操作符重载(operator关键字)
C++ 中友元的用法: 1.在类中使用friend关键字声明 2.类的友元可以是其它类或者具体函数 3.友元不是类的一部分 4.友元不受类中访问级别的限制 5.友元可以直接访问具体类中的所有成员. 友 ...
- java中代码块和构造方法以及普通方法的代码执行顺序总结
说实话,这块真的不好理解啊~都怪jvm 执行顺序搞这么复杂,哼╭(╯^╰)╮ 但是 我们能怎么办,只能研究呗!!! !:首先,毫无置疑的,静态代码块在加载时就执行了,所以肯定是最先执行的.... ...
- Tomcat 设置80端口
1:修改tomcat配置 vi /usr/local/tomcat/conf/server.xml 找到 Connector port="8080" protocol=" ...
- mybatis字符#与字符$的区别
问题:使用in查询查询出一批数据,in查询的参数是字符串拼接的.调试过程中,把mybatis输出的sql复制到navicat中,在控制台将sql的参数也复制出来,替换到sql的字符 '?' 的位置,执 ...
- Nginx如何配置反向代理
server { listen 80; server_name 代理域名; location / { proxy_pass 应用域名:应用端口; proxy_set_header Host $host ...
- 浙大数据结构课后习题 练习二 7-3 Pop Sequence (25 分)
Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, ..., N and p ...
- Turing Tree HDU - 3333 (树状数组,离线求区间元素种类数)
After inventing Turing Tree, 3xian always felt boring when solving problems about intervals, because ...