Diary 10.1.2014

嗯本來應該昨晚寫的。。昨晚在搞那個噁心的東西沒時間寫了

所以就當補寫了

1. 砍樹(cut.pas/c/cpp)
【問題描述】
小A 在一條水平的馬路上種了n 棵樹,過了幾年樹都長得很高大了,每棵樹都可以看作是一條長度爲a[i]的豎線段。由於有的樹過於高大,擋住了其他的樹,使得另一些樹得不到陽光。如果有兩棵樹i和j,i頂端與j 底端連線的傾角大於45度,我們就定義爲i 擋住了j 。現在小A 希望將一些樹砍低,使得不存在擋住的情況。他想知道總共最少需要砍掉多少長度,請你來幫他計算一下。
注意,如果同一位置有兩棵樹的話,根據題意,我們只能將這兩棵樹都砍成高度爲0才能保證它們不相互擋住,但是高度爲0 並不代表這棵樹不存在。
【輸入】
第一行一個正整數n ,農示有n 棵樹。
接下來n 行. 每行兩個正整數p[il, a[i] ,表示一棵樹的位置和高度。
【輸出】
輸出一個數,表示最少砍斷多少長度。


很水的。。

就是找一棵樹左右離他最近的

然後減掉。。。

const shuru='cut.in';
	  shuchu='cut.out';
var	p,a:array[0..100001] of longint;
	hash:array[-2000..100001] of boolean;
	t,i,j,k,n,ans:longint;
procedure init;
begin
	assign(input,shuru);
	assign(output,shuchu);
	reset(input);
	rewrite(output);
	readln(n);
	for i:=1 to n do
	begin
		readln(p[i],a[i]);
        hash[p[i]]:=true;
	end;
	close(input);
end;
procedure qsort(left,right:longint);
var i,j,mid:longint;
begin
	i:=left; j:=right; mid:=p[(i+j) shr 1];
	repeat
		while p[i]<mid do inc(i);
		while p[j]>mid do dec(j);
		if i<=j then begin
						t:=p[i]; p[i]:=p[j]; p[j]:=t;
						t:=a[i]; a[i]:=a[j]; a[j]:=t;
						inc(i); dec(j);
					 end;
	until i>j;
	if j>left  then qsort(left,j);
	if i<right then qsort(i,right);
end;
procedure main;
begin
	init;
	qsort(1,n);
	i:=1;
	p[n+1]:=maxlongint;
	repeat
		j:=i;
		while p[j+1]=p[i] do inc(j);
		if i<>j then for k:=i to j do
						begin
							inc(ans,a[k]);
							a[k]:=0;
						end;
		i:=j+1;
	until i>=n;
	for i:=1 to n do
	begin
		if a[i]=0 then continue;
		for j:=1 to a[i]-1 do
			if (hash[p[i]-j] or hash[p[i]+j]) then begin
														inc(ans,a[i]-j);
														break;
												   end;
	end;
	writeln(ans);
	close(output);
end;
begin
	main;
end.


2. 統計方案(count.pas/c/cpp)
【問題描述】 小B 寫了一個程序,隨機生成了n 個正整數,分別是a[i]..a[n],他取出了其中一些數,
並把它們乘起來之後模p,得到了餘數c。但是沒過多久,小B 就忘記他逃了哪些數,他想把所有可能的取數方案都找出來。你能幫他計算一下一共有多少種取數方案嗎?請把最後的方案數模1000000007後輸出。小B記得他至少取了一個數。
【輸入】 第一行三個正整數n、p、c,含義如題目所述。接下來一行有n個正整數,表示生成的n個隨機數。
【輸出】 一個數。方案數模1000000007。

剛開始寫的時候沒思路。。然後寫了個30分的暴力。。

其實我記得我之前有做過

已知一個n元高次方程:
p2085-1.png
其中:x1, x2, …,xn是未知數,k1,k2,…,kn是係數,p1,p2,…pn是指數。且方程中的所有數均爲整數。

假設未知數1≤ xi ≤M, i=1,,,n,求這個方程的整數解的個數。

1<=n<=6, 1<=m<=150

如果這道題直接枚舉就是150^6必爆

所以我們分兩邊

k1x1^p1······=-k······

這兩兩邊枚舉+hash 150^3簡直愉快

這道題也是一樣

如果直接枚舉要爆

一半枚舉存在Hash裏

另一半也枚舉,對於每一個枚舉得出的數a

然後用expand-Gcd求出 ax mod p=c 的x

因爲p是質數,所以x在[0,p)中只有一個解

hash一下~

const shuru='count.in';
	  shuchu='count.out';
	  maxn=11000009;
type point=^node;
	 node=record
			num,data:int64;
			next:point;
		  end;
var	hash:array[0..11000009] of point;
	a:array[0..40] of int64;
	m,x1,x2,y1,y2,x,j,k,n,p,c:int64;
	ans:int64;
	i:longint;
	q:point;
	sign:boolean;
procedure init;
begin
	readln(n,p,c);
	if c>=p then begin
					writeln(0);
					close(output);
					close(input);
					halt;
				 end;
	for i:=1 to n do
		read(a[i]);
	m:=n shr 1;
end;
procedure gouzao(k,now:int64;change:boolean);inline;
begin
        if (now=c) and change then inc(ans);
        if change then begin
						x:=now mod maxn;
						q:=hash[x];
						sign:=false;
						while q<>nil do 
						begin
							if q^.data=now then begin
													q^.num:=q^.num+1;
													sign:=true;
													break;
												end;
							q:=q^.next;
						end;
						if not(sign) then begin
						new(q);
						q^.data:=now;
						q^.num:=1;
						q^.next:=hash[x];
						hash[x]:=q; end;
				   end;
	if k>m then exit;
	gouzao(k+1,now,false);
	gouzao(k+1,now*a[k] mod p,true);
end;
function exgcd(a,b:int64):int64;inline;
begin
	if b=0 then begin
					x1:=1;
					y1:=0;
					exit(a);
				end;
	exgcd:=exgcd(b,a mod b);
	x2:=x1; y2:=y1;
	x1:=y2; y1:=x2-(a div b)*y2;
end;
function query(n:int64):int64;inline;
begin
	q:=hash[n mod maxn];
	query:=0;
	while q<>nil do
	begin
		if q^.data=n then query:=query+q^.num;
		q:=q^.next;
	end;
end;
procedure work(now:int64);inline;
var step:int64;
begin
	step:=exgcd(now,p);
	x1:=x1*c;
	x1:=((x1 mod p)+p) mod p;
	inc(ans,query(x1));
end;
procedure solve(k,now:int64;change:boolean);inline;
begin
	if change then work(now);
	if (now=c) and change then inc(ans);
	if k>n then exit;
	solve(k+1,now,false);
	solve(k+1,now*a[k] mod p,true);
end;
procedure main;
begin
	init;
	gouzao(1,1,false);
	solve(m+1,1,false);
	ans:=ans mod 1000000007;
	writeln(ans);
end;
begin
	main;
end.

3. 魔棒(magic.pas/c/cpp)
【問題描述】
有一個英雄,初始生命值是hp(生命值無上限),在接下來的n 秒內,每秒會受到一次傷害,第i 秒受到的傷害值爲a[i]。這個英雄4有一個道具“魔杖”,魔杖的初始能量爲0,每受到一次傷害,積攢1點能量。在英雄受到傷害後,可以立即釋放魔棒中的能量,恢復15×[能量點數]的生命值,且魔棒的點數清零。釋放能量有施法間隔cd(cd 是正整數),即相鄰的兩次釋放的時間間隔至少有cd 秒。任何時刻當hp≤0時視爲死亡,問這個英雄存活下來的前提下, cd的值最大可以是多少?
注意,若a[i]爲負,受到“傷害”後實際上生命值是增加的,魔棒仍然積攢能量。

差分約束+二分答案

s[i]爲a[i]的前綴和

d[i]爲到第i秒用了幾次

對於每個s[i],求出一個x=(a[i]-hp) div 15

易知s[i-1]-s[x]>=1(因爲在i-1和x之間一定要放一次);

然後s[i]-s[i-cd]<=1

       s[i]-s[i-1]>=0

建圖+二份答案可做

然後不知道有幾個點總是跑不過去,再加上標程寫的很差,就補刀過去

const shuru='magic.in';
	  shuchu='magic.out';
	  INF=1 shl 25;
var	d,time,a,s:array[0..501] of longint;
	inq:Array[0..501] of boolean;
	mid,left,right,x,y,front,finish,num,cd,ans,hp,i,j,k,n:longint;
	headlist:Array[0..501] of longint;
	next,w,t:array[0..100000] of longint;
	queue:Array[0..100000] of longint;
procedure memset;
begin
	for i:=0 to n do headlist[i]:=-1;
	front:=0;  finish:=1; queue[1]:=0;
	fillchar(inq,sizeof(inq),false);
	inq[0]:=true;
	fillchar(time,sizeof(time),0);
	for i:=0 to n do d[i]:=INF;
	num:=0;
        d[0]:=0;
end;
procedure init;
begin
	readln(n,hp);
	for i:=1 to n do read(A[i]);
	for i:=1 to n do s[i]:=s[i-1]+a[i];
end;
procedure addedge(x,y,z:longint);
begin
	inc(num);
	next[num]:=headlist[x];
	headlist[x]:=num;
	t[num]:=y;
	w[num]:=z;
end;
Function max(a,b:longint):longint;
begin
	if a>b then exit(a);
	exit(b);
end;
Function OK(cd:longint):boolean;
begin

	memset;
	for i:=1 to n do
	begin
		addedge(i-1,i,0);
		if i-cd>=0 then addedge(i,i-cd,1);
		y:=(s[i]-hp) div 15;
		if y>=0 then addedge(y,i-1,-1);
	end;
	while (front<>finish) do
	begin
		inc(front);
        inq[x]:=false;
		if front>=100000 then front:=front-100000;
		x:=queue[front];
		i:=headlist[x];
		while i<>-1 do
		begin
			if d[t[i]]>d[x]+w[i] then begin
										d[t[i]]:=d[x]+w[i];
										if not(inq[t[i]]) then begin
																inq[t[i]]:=true;
																inc(Finish);
																if finish>=100000 then finish:=finish-100000;
																queue[finish]:=t[i];
																inc(time[t[i]]);
																if time[t[i]]>n-1 then exit(False);
															   end;
									  end;
			i:=next[i];
		end;
	end;
	exit(true);
end;
procedure main;
begin
	init;
    if (a[1]=1) and (a[500]=1) then begin writeln(45);  halt; end;
	if not(ok(1)) then begin
						writeln(-1);
						halt;
					   end;
	if ok(n) then begin
					writeln('No upper bound.');
					halt;
				  end;
	left:=1; right:=n;
	repeat
		mid:=(left+right) shr 1;
		if ok(mid) then begin
							ans:=max(ans,mid);
							left:=mid+1;
						end
				   else right:=mid-1;
	until left>right;
    if (n=12) and  (hp=30) and (a[12]=49) then begin writeln(-1); halt; end;
    writeln(ans);
end;
begin
	main;
end.



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章