NOIP2011解题报告-Day2

计算系数

        二项式定理。杨辉三角堆组数+快速幂。Noip的时候还没学二项式定理。。。

 1 const p=10007;maxk=1000;
 2 var  a,b,k,n,m:longint;
 3 function C(k,m:longint):longint;
 4          var f:array[0..maxk,0..maxk] of longint;
 5              i,j,n:longint;
 6          begin
 7          n:=k-m;
 8          if(n=0)or(m=0)then exit(1);
 9          for i:=0 to n do f[i][0]:=1;
10          for j:=0 to m do f[0][j]:=1;
11          for i:=1 to n do
12            for j:=1 to m do
13              f[i][j]:=(f[i-1][j]+f[i][j-1])mod p;
14          exit(f[n][m]);
15          end;
16 function exp(a,b:longint):longint;
17          var ans,temp:int64;
18          begin
19          ans:=1;temp:=a;
20          while b<>0 do
21            begin
22            if((b and 1)=1)then ans:=(ans*temp)mod p;
23            temp:=(temp*temp)mod p;
24            b:=b shr 1;
25            end;
26          exit(ans);
27          end;
28 begin
29   readln(a,b,k,n,m);
30   if(n=0)and(m=0)
31     then begin
32          writeln(0);
33          halt;
34          end;
35   a:=a mod p;b:=b mod p;
36   writeln(C(k,m)*int64(exp(a,n))*exp(b,m) mod p);
37 end.

聪明的质检员

        考场上没看懂题目。。。

        发现Y是关于w的减函数,于是二分W,维护前缀和在O(n)的复杂度求出Y。总复杂度O(N log(max{wi}))

PS:w离散化后二分复杂度应该是O(N log(N))时间没有快多少,可能出现在对数上影响不大.

  1 program qc;
  2 uses math;
  3 var n,m,i,low,high,mid,tot:longint;
  4     s,y:int64;
  5     l,r,w,v,sta:array[0..200000] of longint;
  6     count,sigmaV:array[0..200000] of int64;
  7     f:array[0..1000000] of boolean;
  8 function calc(mid:longint):int64;
  9          var i:longint;
 10          begin
 11          calc:=0;count[0]:=0;sigmaV[0]:=0;
 12          for i:=1 to n do
 13            begin
 14            count[i]:=count[i-1];
 15            sigmaV[i]:=sigmaV[i-1];
 16            if w[i]>mid
 17              then begin
 18                   inc(count[i]);
 19                   inc(sigmaV[i],v[i]);
 20                   end;
 21            end;
 22          for i:=1 to m do
 23            inc(calc,(count[r[i]]-count[l[i]-1])*
 24                     (sigmaV[r[i]]-sigmaV[l[i]-1]));
 25          end;
 26 begin
 27 high:=0;low:=maxlongint;
 28 readln(n,m,s);
 29 for i:=1 to n do
 30   begin
 31   readln(w[i],v[i]);
 32   low:=min(w[i],low);
 33   high:=max(w[i],high);
 34   f[w[i]]:=true;
 35   end;
 36 for i:=1 to m do
 37   readln(l[i],r[i]);
 38 //===lisuanhua===
 39 tot:=1;sta[tot]:=low-1;
 40 for i:=low to high do
 41   if f[i] then begin
 42                inc(tot);
 43                sta[tot]:=i;
 44                end;
 45 inc(tot);sta[tot]:=high+1;
 46 //===============
 47 low:=1;high:=tot;
 48 while low+1<high do
 49   begin
 50   mid:=(low+high)>>1;
 51   y:=calc(sta[mid]);
 52   if y>s then low:=mid
 53          else high:=mid;
 54   end;
 55 writeln(min(abs(s-calc(sta[low])),abs(s-calc(sta[high]))));
 56 end.
 57 //================================================
 58 program qc;
 59 uses math;
 60 var n,m,i,low,high,mid:longint;
 61     s,y:int64;
 62     l,r,w,v:array[0..200000] of longint;
 63     count,sigmaV:array[0..200000] of int64;
 64 function calc(mid:longint):int64;
 65          var i:longint;
 66          begin
 67          calc:=0;count[0]:=0;sigmaV[0]:=0;
 68          for i:=1 to n do
 69            begin
 70            count[i]:=count[i-1];
 71            sigmaV[i]:=sigmaV[i-1];
 72            if w[i]>mid
 73              then begin
 74                   inc(count[i]);
 75                   inc(sigmaV[i],v[i]);
 76                   end;
 77            end;
 78          for i:=1 to m do
 79            inc(calc,(count[r[i]]-count[l[i]-1])*
 80                     (sigmaV[r[i]]-sigmaV[l[i]-1]));
 81          end;
 82 begin
 83 high:=0;low:=maxlongint;
 84 readln(n,m,s);
 85 for i:=1 to n do
 86   begin
 87   readln(w[i],v[i]);
 88   low:=min(w[i],low);
 89   high:=max(w[i],high);
 90   end;
 91 for i:=1 to m do
 92   readln(l[i],r[i]);
 93 dec(low);inc(high);
 94 while low+1<high do
 95   begin
 96   mid:=(low+high)>>1;
 97   y:=calc(mid);
 98   if y>s then low:=mid
 99          else high:=mid;
100   end;
101 writeln(min(abs(s-calc(low)),abs(s-calc(high))));
102 end.

观光公交

首先考虑k=0;如何计算出答案

        Leave[i]为最早允许离开i的时间 leave[i]=max{t[j]}(a[j]=i)

        可以再读入数据时处理出来leave[a[i]]:=max(T[i],leave[a[i]]);

        Get[i]为到达i站时间 Get[i]=max(get[i-1],leave[i-1])+D[i-1];

枚举计算每个旅客的旅行时间

        Ans=sigma(i=1..m) (get[b[i]]-T[i])

        K=1时枚举给哪个D[i]减一即可

满分做法:贪心

        发现给某个D[i]减一后会使后面连续的人等车的车站的乘客提前上车。直到一个车站leave[j]>get[j](车等人),人来的时间是不能跟改变的。所以提前了上车时间的旅客提前了的一分钟要在等人上浪费掉,所以旅行时间不会减小。也就是说令right[i]为i后面第一个满足车等人的站点。

        那么在i+1到right[i]这个区间内下车的人的旅行时间都会减小一。维护下车人数的前缀和S。

        给D[i]减一所减小的答案为S[right[i]]-S[right[i]]。每次找到最大的加速。找最大可以O(n)暴力,也可以维护堆O(log n)。减的时候有3种情况

        1.k很小全部用掉

  1.         2.D[i]很小全部减掉(必须保证每个D[i]>=0)
  2.         3.i+1..tright[i]中最小的Get[j]-Leave[j](把这个值减成负的会破坏现有的区间的关系,减成负的就变成车等人了)

从这3个值中取最小值用掉

然后O(n)重新计算i..right[i]-1的right值

没写堆,在RQ上过了。Noip的数据很厚道。

 

 

 1 program bus;
 2 uses math;
 3 CONST
 4       maxn=1000;
 5       maxm=10000;
 6       maxk=1000000;
 7 var a,b,t:array[0..maxm] of longint;
 8     right,tot,s,cnt,GetIn,GetOff,get,leave,d:array[0..maxn+1] of longint;
 9     p,count,n,m,k,i,j,maxcnt,maxi,temp:longint;
10     ans:int64;
11 BEGIN
12 read(n,m,k);
13 for i:=1 to n-1 do read(D[i]);
14 for i:=1 to m do
15   begin
16   read(t[i],a[i],b[i]);
17   inc(GetOff[b[i]]);inc(GetIn[a[i]]);
18   leave[a[i]]:=max(leave[a[i]],t[i]);
19   end;
20 for i:=2 to n do
21   get[i]:=max(leave[i-1],get[i-1])+D[i-1];
22 p:=1;
23 for i:=1 to n do
24   begin
25   while((p<n)and(leave[p]<get[p]))or(p<=i)do inc(p);
26   right[i]:=p;
27   end;
28 for i:=1 to n do
29   s[i]:=s[i-1]+GetOff[i];
30 while k>0 do
31   begin
32   maxcnt:=0;
33   for i:=1 to n-1 do
34     if (s[right[i]]-s[i]>maxcnt)and(D[i]>0)
35       then begin
36            maxcnt:=s[right[i]]-s[i];
37            maxi:=i;
38            end;
39   if maxcnt=0
40     then break
41     else begin
42          temp:=maxlongint;j:=maxi+1;
43          while(j<n)and(leave[j]<get[j])do
44            begin
45            temp:=min(get[j]-leave[j],temp);
46            inc(j);
47            end;
48          temp:=min(D[maxi],temp);temp:=min(k,temp);
49          dec(k,temp);dec(D[maxi],temp);
50          for j:=maxi+1 to right[i] do
51            get[j]:=max(get[j-1],leave[j-1])+D[j-1];
52          p:=maxi;count:=GetOff[maxi];
53          for j:=maxi to right[i]-1 do
54            begin
55              while((p<n)and(leave[p]<get[p]))or(p<=j)do inc(p);
56              if p>=right[j] then break;
57              right[j]:=p;
58            end;
59          end;
60   end;
61 get[1]:=leave[1];get[n]:=max(get[n],leave[n]);
62 for i:=1 to m do
63   inc(ans,get[b[i]]-t[i]);
64 writeln(ans);
65 END.

 

posted @ 2012-08-13 21:31  ljlin  阅读(2308)  评论(1编辑  收藏  举报