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.



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