计算系数
二项式定理。杨辉三角堆组数+快速幂。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很小全部用掉
- 2.D[i]很小全部减掉(必须保证每个D[i]>=0)
- 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.