noip2016模拟赛day7

T1:carpet

  题目:给定一个N点M边的无向图,每条边有权值W,选择K条边,保证点与点之间最多一条路径且W的和最大

  数据范围:对于100%的数据,n,m≤100000

  思路:最大生成树。。。。。。。

代码:

const
  maxn=100100;
type
  rec=record
        x,y,w:longint;
      end;
var
  a:array[1..maxn] of rec;
  f:array[1..maxn] of longint;
  n,m,k,i:longint;
  function find(x:longint):longint;
  begin
    if f[x]=x then exit(f[x]);
    f[x]:=find(f[x]);
    exit(f[x]);
  end;
  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;
  procedure solve;
  var
    fx,fy,i:longint;
    ans:int64;
  begin
    ans:=0;
    for i:=1 to n do f[i]:=i;
    for i:=1 to m do
    begin
      fx:=find(a[i].x);
      fy:=find(a[i].y);
      if fx<>fy then
      begin
        f[fx]:=fy;
        ans:=ans+a[i].w;
        dec(k);
        if k=0 then break;
      end;
    end;
    writeln(ans);
  end;
begin
  readln(n,m,k);
  for i:=1 to m do readln(a[i].x,a[i].y,a[i].w);
  qsort(1,m);
  solve;
end.


T2:calc

  题目:定义一种运算!:N!K=(N-1)!K*N!(K-1)(N>0 and K>0);

N!K=1(N=0); N!K=N(K=0)。给定N,K,求N!K的约数个数,答案对1e9+9取余

  数据范围:对于100%的数据,n≤1000,k≤100

  思路:那么对于一个数的约数个数,由唯一分解定理可得,为各个质因数的次方数+1的乘积,再由给定的表达式发现,N!K的所有运算中只存在乘法,所以可以先预处理出1000以内的所有质数(也就168个),然后用f[i,j]记录每一项各个质数的指数,相加即可

代码:

const
  mo=1000000009;
var
  f:array[0..1000,0..100,1..168] of longint;
  p:array[1..168] of longint;
  n,k,i,m,t,j,l:longint;
  ans:qword;
  procedure pre;
  var
    i,j,t:longint;
    flag:boolean;
  begin
    p[1]:=2; t:=1;
    for i:=3 to 1000 do
    begin
      flag:=true;
      for j:=2 to trunc(sqrt(i)) do
        if i mod j=0 then flag:=false;
      if flag then
      begin
        inc(t);
        p[t]:=i;
      end;
    end;
  end;
  function find(x:longint):longint;
  var
    i:longint;
  begin
    for i:=1 to 168 do if x=p[i] then exit(i);
  end;
begin
  pre;
  readln(n,k);
  fillchar(f,sizeof(f),0);
  for i:=1 to n do
  begin
    m:=i;
    for j:=2 to i do
    begin
      if m mod j=0 then
      begin
        t:=find(j);
        while m mod j=0 do
        begin
          inc(f[i,0,t]);
          m:=m div j;
        end;
      end;
    end;
  end;
  for i:=1 to n do
    for j:=1 to k do
      for l:=1 to 168 do
        f[i,j,l]:=(f[i-1,j,l]+f[i,j-1,l]) mod mo;
  ans:=1;
  for i:=1 to 168 do ans:=(ans*(f[n,k,i]+1)) mod mo;
  writeln(ans);
end.

T3:railway(题目描述好长好长。。。。。。)

  题目:


  简化:其实就是一个无向图的边都有颜色,每一种颜色都按如阶梯水费那般收取费用,最后让你求最小的费用(如果可以到达)

  思路:对于一家铁路公司,我们可以首先使用 Floyd 算法求出任 意两点 x, y 间只经过属于该家铁路公司铁路的最短路,那么在新 图中我们在 x, y 间加一条 x 到 y 最短路对应的花费为边权的边。 接下来只要在新图中使用 Floyd 算法求出任意两点间的最小花费就可以了。

代码:

const
  maxc=20;
  maxn=100;
  maxm=10000;
  maxp=50;
  maxw=200000;
  inf=1061109567;
type
  rec=record
        x,y,w,b:longint;
      end;
var
  f:array[1..maxc,1..maxn,1..maxn] of longint;
  fa:array[1..maxn] of longint;
  a:array[1..maxm] of rec;
  p:array[1..maxc] of longint;
  q,r:array[1..maxc,1..maxp] of longint;
  cost:array[1..maxc,0..maxw] of longint;
  d:array[1..maxn,1..maxn] of longint;
  n,m,c,s,t,i,j,k,l,x,y,w,b,fx,fy,fs,ft:longint;
  function min(a,b:longint):longint;
  begin
    if a<b then exit(a) else exit(b);
  end;
  function find(x:longint):longint;
  begin
    if x=fa[x] then exit(fa[x]);
    fa[x]:=find(fa[fa[x]]);
    exit(fa[x]); 
  end;
begin
  fillchar(f,sizeof(f),$3f);
  fillchar(d,sizeof(d),$3f);
  readln(n,m,c,s,t);
  for i:=1 to m do
  begin
    readln(x,y,w,b);
    a[i].x:=x; a[i].y:=y; a[i].w:=w; a[i].b:=b;
    f[b,x,y]:=w;
    f[b,y,x]:=w;
  end;
  for i:=1 to n do fa[i]:=i;
  for i:=1 to m do
  begin
    x:=a[i].x; y:=a[i].y;
    fx:=find(x); fy:=find(y);
    if fx<>fy then fa[fx]:=fy;
  end;
  fs:=find(s); ft:=find(t);
  if fs<>ft then begin writeln(-1); halt; end;
  for i:=1 to c do read(p[i]);
  for i:=1 to c do
  begin
    for j:=1 to p[i]-1 do read(q[i,j]); q[i,p[i]]:=inf;
    for j:=1 to p[i] do read(r[i,j]);
    l:=1;
    for j:=1 to maxw do
    begin
      if j>q[i,l] then inc(l);
      cost[i,j]:=cost[i,j-1]+r[i,l];
    end;
  end;
  for l:=1 to c do
    for k:=1 to n do
      for i:=1 to n do
        for j:=1 to n do
          f[l,i,j]:=min(f[l,i,j],f[l,i,k]+f[l,k,j]);
  for i:=1 to n do
    for j:=1 to n do
      for k:=1 to c do
        if f[k,i,j]<>inf then d[i,j]:=min(d[i,j],cost[k,f[k,i,j]]);
  for k:=1 to n do
    for i:=1 to n do
      for j:=1 to n do
        d[i,j]:=min(d[i,j],d[i,k]+d[k,j]);
  writeln(d[s,t]);
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值