jzoj 模拟赛总结(2017.07.12)

来源:互联网 发布:搜狗输入法for ubuntu 编辑:程序博客网 时间:2024/06/05 12:50

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.
原创粉丝点击