T1.
蚂蚁:
有N只蚂蚁以每秒1cm的速度在长为Lcm的竿子上爬行。当蚂蚁爬到竿子的端点时就会掉落。由于竿子太细,两只蚂蚁相遇时,它们不能交错通过,只能各自反向爬回去。对于每只蚂蚁,我们知道它距离竿子左端的距离xi,但不知道它当前的朝向。请计算各种情况当中,所有蚂蚁落下竿子所需的最短时间和最长时间。
例:
竿子长10cm,3只蚂蚁位置为2 6 7,最短需要4秒(左、右、右),最长需要8秒(右、右、右)。
1 <= L <= 10^9, 1 <= N <= 50000
0 < A[i] < L
对于10%的数据n≤1
对于20%的数据n≤2
对于50%的数据n≤5
对于60%的数据n≤50
对于70%的数据n≤500
对于80%的数据n≤5000
对于100%的数据n≤50000
题解:
相信很多人会用搜索去裸掉,当然会超时,这时候我们透过问题看本质。
我们发现,对于一只蚂蚁X与另一只Y相撞,其实就是Y把X的剩下路程走了,X把Y的剩下路程走了,而对于时间的花费则是不变的。
这时候我们就发现直接枚举找最大最小就可以了,枚举每个蚂蚁向左向右的路程x[i],y[i],然后判断最大最小max[i],min[i]
得出最后的答案就是
ans_max=max[i]中的最大值
ans_min=min[i]中的最小值
过程实现的时间复杂度:O(N)
uses math;
var
x,l,n,i,cmax,cmin:longint;
begin
assign(input,'t1.in'); reset(input);
assign(output,'t1.out'); rewrite(output);
cmax:=0;
cmin:=0;
readln(n,l);
for i:=1 to n do
begin
readln(x);
cmin:=max(cmin,min(l-x,x));
cmax:=max(cmax,max(l-x,x));
end;
writeln(cmin,' ',cmax);
close(input); close(output);
end.
T2.
max:
题目大意:
一个正整数一般可以分为几个互不相同的自然数的和,如3=1+2,4=1+3,5=1+4=2+3,6=1+5=2+4,…。
现在你的任务是将指定的正整数n分解成m个(m>=1)互不相同的自然数的和,且使这些自然数的乘积最大。
30%的数据 3<=n<=100
100%的数据 3≤n≤10000
题解:
找规律+贪心+数学+高精度:
我们发现,如果分出一个1,不仅浪费了分配数量,对乘积还没有意义,显然是不优的。
然后我们发现分的越多其实就越优,所以我们可以将sum从2开始加,直到
sum+i>N就退出,然后2~i-1就是答案,不过注意
如果sum
var
k:array [0..201] of longint;
b:array [0..501] of boolean;
ans:array [0..100001] of longint;
i,j,n,sum:longint;
procedure cheng(x:longint);
var
i:longint;
j:longint;
begin
j:=0;
for i:=1 to ans[0] do
begin
ans[i]:=ans[i]*x+j;
j:=ans[i] div 100;
ans[i]:=ans[i] mod 100;
end;
ans[ans[0]+1]:=j;
ans[0]:=ans[0]+1;
while ans[ans[0]]=0 do dec(ans[0]);
end;
begin
assign(input,'max.in'); reset(input);
assign(output,'max.out');rewrite(output);
readln(n);
i:=2; k[0]:=0;
while sum+i<=n do
begin
inc(k[0]);
k[k[0]]:=i;
sum:=sum+i;
b[i]:=true;
inc(i);
end;
j:=k[0]; i:=1;
while i<=n-sum do
begin
if not(b[k[j]+1])
then begin
b[k[j]+1]:=true;
b[k[j]]:=false;
k[j]:=k[j]+1;
dec(j);
if j=0 then j:=k[0];
end;
inc(i);
end;
ans[0]:=1; ans[1]:=1;
for i:=1 to k[0] do
begin
write(k[i],' ');
cheng(k[i]);
end;
writeln;
for i:=ans[0] downto 1 do
begin
if i<>ans[0] then
if ans[i]<=9 then write('0');
write(ans[i]);
end;
close(input); close(output);
end.
T3.
Famer KXP在与他的好朋友Famer John玩一个游戏,规则如下:KXP站在起点,桌子上放置着一排物品,共N个,每个物品都有它的质量和距离起点的位置。KXP的基础分=最远物品距离b[y]*2+拿的物品的质量和Σa[i],最终分数=最远物品距离b[y]*2+拿的物品的质量a[y]和*Y(Y为该物品是第Y个被拿的)M次询问,每次KXP想提前知道自己在拿X个物品时基础分最高时最终分数为多少,若在拿K个时有多种情况能达到最高基础分则只输出X小于K时的情况(即发现有多种情况就立即结束程序),希望你帮忙解决。(K不一定被询问)
a,b无重复,询问从小到大
30% 0 < M < N < 10
50% 0 < M < N < 2500
100% 0 < M < 3000 < N < 6000
100% 答案小于2^61 0 < a,b < 10^5 询问数X严格小于N
(数据随机,高兴点)
题解:
不知道。。。
T4.
围攻:
军队共有N个单位,一个接着一个排成一排,每个单位可以是士兵,或者是战车,这样的组合可以爆发出意想不到的强大战斗力;但有一点,两辆战车不能相邻,否则会发生剐蹭等不好的事故。刘邦希望知道这N个单位的军队都多少种不同的排列方法,以便在战场中随机应变。两种军队的排列方法是不同的,当且仅当某一个单位对应不同,如:第i位这种是士兵,那种是战车……
对于30%的数据:N≤15;
对于70%的数据:N≤10^6;
对于100%的数据:N≤10^18。
题解:
设士兵是0,战车是1
对于30分的数据,直接搜索即可
a[i]=0 就 dfs(dep+1,0) , dfs(dep+1,1)
a[i]=1 dfs(dep+1,0)
时间复杂度:O(3^N)
70分:
不难推DP:
f[i,0]表示到第i个位置为士兵的方案总数。
f[i,1]表示到第i个位置为战车的方案总数。
然后
f[i,0]:=f[i-1,1]+f[i-1,0]
f[i,1]:=f[i-1,0]
然后ans=f[n,0]+f[n,1]
时间复杂度:O(n)
而对于100分的点:
我们先推导一下:
设g[i]为到第i步总的方案总数。
则g[i]=f[i,1]+f[i,0]
=f[i-1,0]+(f[i-1,0]+f[i-1,1])
=(f[i-2,0]+f[i-2,1])+(f[i-1,0]+f[i-1,1])
=g[i-2]+g[i-1]
就是斐波那契数列!!!!
然后我们发现对于这种时间复杂度为O(n)的算法,对于大的数据显然是不可得的,
所以我们考虑用矩阵乘法去优化。
分析:
因为题目我们推出了f[1]=2,f[2]=3
所以我们只需要求出左图二阶矩阵的n-2次方,然后与其按矩阵乘法相乘即可。
然后这个过程我们可以因为是求幂次,所以我们可以用快速幂优化
时间复杂度:O(log N)
const
modn=100000007;
var
a,b,c:Array [0..2,0..2] of int64;
n:int64;
procedure ksm(x:int64);
var
i,j,k:longint;
begin
a:=b;
while x>0 do
begin
if x mod 2=1 then
begin
fillchar(c,sizeof(c),0);
for i:=1 to 2 do
for j:=1 to 2 do
for k:=1 to 2 do
c[i,j]:=c[i,j]+a[i,k]*b[k,j] mod modn;
a:=c;
end;
fillchar(c,sizeof(c),0);
for i:=1 to 2 do
for j:=1 to 2 do
for k:=1 to 2 do
c[i,j]:=c[i,j]+b[i,k]*b[k,j] mod modn;
b:=c;
x:=x>>1;
end;
end;
begin
assign(input,'siege.in'); reset(input);
assign(output,'siege.out'); rewrite(output);
readln(n);
if n<=2
then writeln(n+1)
else begin
b[1,1]:=0; b[1,2]:=1;
b[2,1]:=1; b[2,2]:=1;
ksm(n-2);
writeln((a[1,1]*2+a[1,2]*3) mod modn);
end;
close(input); close(output);
end.