嗯本來應該昨晚寫的。。昨晚在搞那個噁心的東西沒時間寫了
所以就當補寫了
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.