您的位置:首页 > 其它

NOIP2016模拟赛 day6

2016-11-07 15:38 162 查看
转移阵地,我们继续(伤害)

---------------------------------------------(我是分割线)-------------------------------------------------

T1:city

  题目:给定一棵最小生成树(保证唯一),求其完全图的最小边权和

  数据规模:对于100%的数据,点数n≤20000

  思路:手动模拟一次,发现对于最后完全图的边分为两种情况,一种是于最小生成树内的,另外一种是新加的。对于所有新加的边,为了保证最小生成树的唯一,设从i->j经过的边长分别为a,b,c,那么显然可得,i到j之间的最小边长min(i,j)=max{a,b,c}+1,考虑最小生成树内的每一条边都会有对答案的贡献,那么将每一条边按权值由大到小排序后,每一条边对于答案的贡献即为(w+1)*siz[fx]*siz[fy]-1,之后将这条边擦去。以上操作均可以用并查集完成。

代码:
<span style="font-size:24px;">const
maxn=40000;
type
rec=record
x,y,w:longint;
end;
var
a:array[1..maxn] of rec;
f,siz:array[1..maxn] of longint;
i,n,fx,fy:longint;
ans:int64;
procedure qsort(l,r:longint);
var
i,j:longint;
mid,tmp:rec;
begin
i:=l; j:=r; mid:=a[(l+r) div 2];
repeat
while a[i].w<mid.w do inc(i);
while a[j].w>mid.w do dec(j);
if i<=j then
begin
tmp:=a[i];
a[i]:=a[j];
a[j]:=tmp;
inc(i);
dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
function find(x:longint):longint;
begin
if f[x]=x then exit(f[x]);
f[x]:=find(f[x]);
exit(f[x]);
end;
begin
readln(n);
for i:=1 to n-1 do readln(a[i].x,a[i].y,a[i].w);
qsort(1,n-1);
for i:=1 to n do f[i]:=i;
for i:=1 to n do siz[i]:=1;
for i:=1 to n-1 do
begin
fx:=find(a[i].x);
fy:=find(a[i].y);
ans:=ans+(a[i].w+1)*siz[fx]*siz[fy]-1;
f[fx]:=fy;
siz[fy]:=siz[fy]+siz[fx];
end;
writeln(ans);
end.
</span>

T2:coin

  题目:给定n种硬币,每种硬币的面值为ai,各有无限个。有T个询问,询问能否用给出的n种硬币凑出面值M,输出最小的硬币个数,否则输出-1

  数据规模:对于100%的数据,n≤100,1≤ai≤10^3,1≤M≤10^16,1≤T≤10^5

  思路:乍一看,怎么感觉都是背包问题,但是一看数据规模就知道没那么简单。换个角度思考,当M在没有到达一个一定的范围之前,无脑拿最大的肯定是最优的,那在进入到一定范围之后,选取最优值即可,而明显那一部分是我们可以预处理的,鉴于M的范围,选择背包预处理1~max(ai)^2,那么ans[M]=op+f[M-op*mx],op=(M-max(ai)^2-1) div mx+1

代码:

<span style="font-size:24px;">const
inf=1684300900;
var
a:array[1..2000] of longint;
f:array[1..2000000] of longint;
n,i,j,t:longint;
m,ans,mx,op,tmp:int64;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
begin
readln(n);
for i:=1 to n do read(a[i]);
mx:=0;
for i:=1 to n do mx:=max(mx,a[i]);
fillchar(f,sizeof(f),100);
for i:=1 to n do f[a[i]]:=1;
for i:=1 to sqr(mx) do
for j:=1 to n do f[i+a[j]]:=min(f[i+a[j]],f[i]+1);
readln(t);
while t>0 do
begin
readln(m);
dec(t);
if (m<=sqr(mx)) then
begin
if f[m]<>inf then writeln(f[m]) else writeln(-1);
continue;
end;
op:=(m-sqr(mx)-1) div mx+1;
if f[m-op*mx]=inf then writeln(-1) else writeln(f[m-op*mx]+op);
end;
end.

</span>

T3:shugo(日常惨案,全部人都报0_(:зゝ∠)_,等后续施工吧)
  题目:SingleLyra是一名考古学家,有一天他发现了远古时期的一段文本,这段文本是一个严格上升的十进制数序列,然而现在所有数字连在了一起,因此SingleLyra只能得到一个十进制字符串。        SingleLyra想恢复出来这段文字,为了更加符合原始文本,需要将序列的最后一个数字尽可能小,在此基础上,要求这个序列的字典序尽量大。(字典序尽量大指的是,如果有相同的方案,要求第一个数最大,若第一个数相同,要求第二个数最大,以此类推)。
 注意:恢复时允许前导0的出现。

  数据规模:对于 30% 的数据:1<=|S|<=2000; 对于 100% 的数据:1<=|S|<=100000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: