嗯本来应该昨晚写的。。昨晚在搞那个恶心的东西没时间写了
所以就当补写了
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.
【问题描述】 小B 写了一个程序,随机生成了n 个正整数,分别是a[i]..a[n],他取出了其中一些数,
并把它们乘起来之后模p,得到了余数c。但是没过多久,小B 就忘记他逃了哪些数,他想把所有可能的取数方案都找出来。你能帮他计算一下一共有多少种取数方案吗?请把最后的方案数模1000000007后输出。小B记得他至少取了一个数。
【输入】 第一行三个正整数n、p、c,含义如题目所述。接下来一行有n个正整数,表示生成的n个随机数。
【输出】 一个数。方案数模1000000007。
刚开始写的时候没思路。。然后写了个30分的暴力。。
其实我记得我之前有做过
已知一个n元高次方程:
其中: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.