JZOJ2017.08.19 B组

59 篇文章 0 订阅

T1

Description

  为降低资料储存的空间或增加资料传送的速度,编码是常用的方法。
假设有一个字符集,每个字符出现的频率是已知的。现在要把每个字符编码成为一个二元字串(例如把“A”编码作101),采用的编码必须合乎以下条件:一个字符的编码不可以是另一个字符的前置(prefix)。前置的定义如下:若一个字串S1为另一个字串S2的前置,则从S2的最后一个字符开始,连续删除一定数量的字符后可以得到S1(S2本身也是S2的前置),举例而言:如果字符“A”的编码是101,而字符“B”的编码为01,则“B”的编码不为“A”编码的前置;如果字符“C”的编码为1100,而字符“D”的是11,则“D”的编码是“C”编码的前置。以下的编码方式可以在符合这个条件下给出最经济的编码,请找出使用下述方法做最经济编码时,一个字符编码的预期长度。

编码法:
1、 如以下所述建立一棵二元树。
先从字符集选取两个出现频率最低的字符作合并,合并后以一个全新的虚拟字符取代这两个字符,新字符的频率等于这两个旧字符频率的总和,并令这两个旧字符为此新字符的两个子树,左右不限。重复以上操作,直至字符集剩下一个字符为止。如下图(i)到(iv)。
2、 再依照以下所述方法将各字符作编码。
由上一步骤所得之二元树,将每个内部节点(internal node)连往左子树的边(edge)标记为“0”,连往右子树的边标记为“1”,如下图(V)所示。一字元的编码即为从树根(root)至此字符,经过的每一个边的标记所成之字串。在此“a”编码作000,“?”编码作01。
在按照上述的编码法完成最经济编码之后,就可以计算这个字符编码的预期长度。首先算出每个字符的预期长度=编码长度×出现频率,然后把所有字符的预期长度结合起来,就可以得到此字符编码的预期长度。下表是上述编码的计算范例。
字符 编码 编码长度 出现频率 预期长度
a 000 3 0.1 0.3
b 001 3 0.1 0.3
? 01 2 0.3 0.6
8 1 1 0.5 0.5
字符编码的预期长度 1.7

Input

  第一行为两整数n和m,分别代表字符集的大小和文章总长度。然后每一个字符分行列出,每行列出一字符出现的次数。
  
Output

  预期一个字符编码的长度,保留至小数点后6位。

思路:

我们将所有数打进堆里面
然后每次取最前面的两个出来,然后将它们的和打进堆
其实就跟合并果子一毛一样的

代码:

#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
struct cmp2
{
    bool operator()(int a,int b)
    {
        return a>b;
    }  
};
priority_queue<int,std::vector<int>,cmp2>p;
long n,len,a,x;
int main()
{
    scanf("%ld%ld",&n,&len);
    for (int i=1;i<=n;i++)
    {
        scanf("%ld",&a);
        p.push(a);
    }
    a=0;
    for (int i=1;i<n;i++)
    {
        int x=p.top();p.pop();
        x=x+p.top();p.pop();p.push(x);
        a=a+x;
    }
    printf("%08f",double(a)/double(len));
}

T2

Description

众所周知,Zjr506是算法之神,因此Ztxz16经常向他请教算法。这一天,Zjr506在教导了Ztxz16关于图论方面的一些算法后,给他出了一道图论题作为家庭作业:
给定N个点,M条无向边,Q个询问,每个询问给定L, R,问连上第L~R条边后,图中有多少联通块(询问之间互不影响)。
Ztxz16智商太低,百思不得其解,只好向你请教这个问题。

Input

第一行输入N M Q
接下来M行每行两个整数代表一条边
接下来Q行每行两个整数代表一个询问

Output

输出Q行,代表这个询问中联通块的个数

思路:

首先我们可以用莫队的分块思想,每100个数分成一块,这样可以大大减少时间复杂度
我们将每次加边的左整数按小到大排,而且在同样的左整数,右整数是递增的
然后我们将不再同一个块和在用一个块的分开处理
在同一个块的:我们直接从左整数到右整数存进并查集,求出最后的联通块
如果不再同一个块的:我们将kuai[a[i].l]*100到a[i].r都存进并查集,然后在枚举剩下多余的数。
我们对于每一个块的在做完操作以后都要撤销,那么我们在并查集里搜到这个数时还原就行了

T3

Description

Zjr506很喜欢猫,某一天他突然心血来潮,想捕捉学校里活动的猫。
为了捕猫,Zjr506在校园中放置了N个木桩,当他见到有猫进入他的狩猎范围后,就会以迅雷不及掩耳的速度在一些木桩之间绕上藩篱以困住这些猫。
一段时间后,Zjr506在绕了M个藩篱后兴高采烈的离开了。作为正义的使者,Ztxz16不忍心看到这些猫受到折磨,于是决定拆除一些藩篱让所有的猫都逃出去。因为Zjr506的巧妙设计,藩篱不会在除木桩之外的地方相交。这些藩篱构成了一些封闭的区域,每一个区域中都有一只猫。
因为Zjr506制造这些藩篱也不容易,所以Ztxz16希望拆除的藩篱总长度尽量小,现在他希望你告诉他最小的总长度。

Input

第一行两个数 n,m ( 2<=n<=10000 , 1<=m<=50000 )
接下来 n 行 , 每行两个整数 xi,yi, 代表第 i 个木桩的坐标 ( − 10000 ≤ xi, yi ≤ 10000).
接下来 m 行,每行两个整数 pi,qi (1 ≤ pj, qj ≤ N) , 代表木桩 pi 与木桩 qi 之间有一个藩篱。

Output

输出一个实数代表答案,当答案与标准答案差的绝对值不超过0.001时认为它是正确的。

思路:

最大生成树。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
double sqr(double x){return x*x;}
struct sz{double v; int l,r;}k[100005];
bool cmp(sz a,sz b){return a.v>b.v;}
int n,m,f[100005],x,y;
double a[100005],b[100005],mx,w;
int gf(int x)
{
    if (f[x]==x) return x;
    f[x]=gf(f[x]);
    return f[x];
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) 
    {
        scanf("%lf%lf",&a[i],&b[i]);
        f[i]=i;
    }
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        w=sqrt(sqr(a[x]-a[y])+sqr(b[x]-b[y]));
        mx+=w; k[i].v=w; k[i].l=x; k[i].r=y;
    }
    sort(k+1,k+m+1,cmp);
    for (int i=1;i<=m;i++)
    {
        x=gf(k[i].l); y=gf(k[i].r);
        if (x!=y)
        {
            f[y]=x;
            mx-=k[i].v;
        }
    }
    printf("%.7lf",mx);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值