jzoj 模拟赛总结(2017.07.14)

来源:互联网 发布:有什么英语翻译软件 编辑:程序博客网 时间:2024/06/06 01:38

T1.
Square :
题目大意:
有一个平面直角坐标系,小D将N个左下角为x1,y1,右上角为x2,y2的方块纸放在这个坐标系中,N个方格纸的都与x轴、y轴平行,Q次查询对于平面直角坐标系中的一个点[x,y]有多少个方格纸覆盖(包括方格纸的边和点)。

30%的数据, N*Q≤10^7。
100%的数据, N,Q≤10^5,0 < x1,y1,x2,y2,x,y≤3000

题解:
30分不难发现,暴力强行枚举判断即可,时间复杂度:O(NQ)
而对于100而言,
其实就是多了一个差分,我们利用差分的思想,每次将输入的x1,y1,x2,y2中
a[x1,y1]+1 a[x2,y2]+1
a[x2+1,y1]-1 a[x1,y2+1]-1

然后我们将上面的做一个前缀和,发现
sum[i,j]=sum[i-1,j]+sum[i,j-1]-sum[i-1,j-1]+a[i,j]

时间复杂度:O(N+Q+max(x2)*max(y2))

var   a,sum:array [0..3001,0..3001] of longint;   x,y,x1,y1,maxx,maxy,i,j,n,m:longint;function max(aa,bb:longint):longint;begin   if aa>bb then exit(aa);   exit(bb);end;begin   assign(input,'square.in'); reset(input);   assign(output,'square.out'); rewrite(output);   readln(n);   for i:=1 to n do   begin        readln(x,y,x1,y1);        inc(a[x,y]);        inc(a[x1+1,y1+1]);        dec(a[x1+1,y]);        dec(a[x,y1+1]);        maxx:=max(maxx,x1);        maxy:=max(maxy,y1);   end;   for i:=1 to maxx do     for j:=1 to maxy do        sum[i,j]:=sum[i,j-1]+sum[i-1,j]-sum[i-1,j-1]+a[i,j];   readln(m);   for i:=1 to m do   begin        readln(x,y);        writeln(sum[x,y]);   end;   close(input); close(output);end.

T2.
算法学习:
给出N个无序不重复的数,再有M个询问,每次询问一个数是否在那N个数中,若在,则ans增加2^K,K为该数在原数列中的位置。
由于ans过大,所以只要求你输出ans mod 10^9+7。

30% 0 < N,M<100
50% 0 < N,M<10000
100% 0 < N,M<100000
输入的数均在2^31 以内

题解:
排序+离散(或二分):
将其排序后离散,然后开个桶去做,因为离散后最坏情况最大值为200000.
当然也可以排序后二分位置。

时间复杂度:O(N+M)

const     modn=1000000007;var     rp,d,lxy,num:array [0..200001] of longint;     iq:Array [0..100001] of longint;     ans,i,j,n,m:longint;procedure qsort(l,r:longint);var     i,j,mid:longint;begin     if l>=r then exit;     i:=l; j:=r;     mid:=num[(l+r) div 2];     repeat          while num[i]<mid do inc(i);          while num[j]>mid do dec(j);          if i<=j then          begin              num[0]:=num[i]; d[0]:=d[i];              num[i]:=num[j]; d[i]:=d[j];              num[j]:=num[0]; d[j]:=d[0];              inc(i); dec(j);          end;     until i>j;     qsort(i,r);     qsort(l,j);end;begin    assign(input,'sfxx.in'); reset(input);    assign(output,'sfxx.out');rewrite(output);     readln(n,m);     iq[0]:=1;     for i:=1 to n do     begin          read(num[i]);          d[i]:=i;          iq[i]:=iq[i-1]*2 mod modn;     end;     iq[0]:=0;     readln;     for i:=n+1 to n+m do     begin          read(num[i]);          d[i]:=i;     end;     qsort(1,n+m);     i:=1; j:=1;     while i<=n+m do     begin          rp[d[i]]:=j;          while num[i]=num[i+1] do          begin               inc(i);               rp[d[i]]:=j;          end;          inc(i);          inc(j);     end;     for i:=1 to n do lxy[rp[i]]:=i;     for i:=n+1 to n+m do       ans:=(ans+iq[lxy[rp[i]]]) mod modn;     writeln(ans);     close(input); close(output);end.

T3.
等飞机:
有一个n列的棋盘,一开始NNS在NNS的这边摆放若干个棋子(摆放的位置由NNS说了算,且有可能n列都不摆棋子),第I列为1表示一开始就放了,不然为0就没放。这个回合算是第1回合,这时候到SG摆放棋子(SG也可以n列都不摆棋子),条件是SG摆放的棋不能和SG上一轮摆的棋矛盾(如下图)。
这里写图片描述
但是,如果SG只在第四列摆棋子的话,那么就和上一轮的不矛盾。这算是第2回合。
SG继续摆棋,即第3回合。然后SG一直继续摆棋子(接下来在任意的一个回合内,SG也可以n列都不摆棋子),直到第L回合结束。如果这L回合没有出现任何的矛盾情况,则算SG赢。
NNS知道SG肯定赢定了,因为这次NNS不想SG这么伤心,故意让SG的,求SG赢的方案数(对100000007取模)

题解:
状压DP:
设f[i,j]表示第i行状态为j时的方案总数。
然后f[i,j]=Σf[i-1,k]为从上一行种状态为k,不过要注意,我们要判断k时候能转换成j。
然后我们的初值,就是f[1,j]=1
然后推得时候,
i从2 to l
j,k从1 to 1 shl n-1
时间复杂度:O(L*2^2N)
很明显会爆,我们优化它
我们发现对于i-1行的某个状态k,如果j and k=0即,j能由k转换,那么
k=k+1 f[i,j]=f[i,j]+f[i-1,k]
不然的话,我们就可以将k累加上j and k
时间复杂度:O(L*2^N*K)
K大大小于2^N

const    modn=100000007;var    f:array [0..51,0..8192] of longint;    d:array [0..13] of longint;    i,j,k,x,n,l,s:longint;begin    assign(input,'old.in'); reset(input);    assign(output,'old.out');rewrite(output);    readln(n,l);    d[1]:=1;    for i:=2 to n+1 do d[i]:=d[i-1]*2;    j:=0;  s:=0;    for i:=0 to d[n+1]-1 do f[1,i]:=1;    for i:=1 to n do    begin          read(x);          if x=1 then s:=s+d[i];    end;    for i:=2 to l do    begin         for j:=0 to d[n+1]-1 do         begin              k:=0;              while k<=d[n+1]-1 do              begin                    if k and j=0                       then begin                                f[i,j]:=(f[i,j]+f[i-1,k]) mod modn;                                inc(k);                            end                       else k:=k+k and j;              end;         end;    end;    writeln(f[l,s]);    close(input); close(output);end.

T4.
毁灭:
题目大意:
毁灭者们有一堆二向箔和光粒,他们把这些分成了n份,支持毁灭地球和毁灭三体的两拨人各派出一个代表。由支持毁灭地球的代表先执行,接着两个代表分别执行。每次执行可以选择一份二向箔和光粒并将他们全部拿走,直到只剩下m份。如果剩下的二向箔和光粒的总数为偶数个,那么三体文明将会先被消灭,否则地球文明将会先被消灭。
两位代表都会尽全力让自己赢。
如果三体先被毁灭则输出“Three-Body”,否则输出“Earth”

对于30%:n<=10
对于100%:n<=500000,0 < m<=n
二向箔和光粒的个数<=1000000
数据组数不会太多

题解:
找规律:
我们分析发现先手赢的条件是最后的和为奇数,那么后手赢的条件是为偶数
分类去讨论:
①如果双方都不能拿,即N=M,那么直接判断
②如果后手能拿掉所有的奇数,那么后手胜
③如果后手能拿掉所有的偶数,并且用掉剩下的操作次数后,剩下偶数,后手胜
④如果先手能拿掉所有的偶数,并且用掉剩下的操作次数后,剩下奇数,先手胜
最后如果上面都不满足,就代表剩下的总有奇数和偶数,那么判断谁拿了最后一次,谁就能胜。
时间复杂度:O(TN)

var    a:array [1..2] of longint;    sum,i,j,x,n,m,ans,p,q:longint;begin    assign(input,'destroy.in'); reset(input);    assign(output,'destroy.out'); rewrite(output);    while not(eof) do    begin         readln(n,m);         a[1]:=0; a[2]:=0;         for i:=1 to n do         begin              read(x);              if odd(x)                 then inc(a[1])                 else inc(a[2]);         end;         readln;         sum:=a[1]+2*a[2];         if n=m then         begin            if odd(sum)               then writeln('Earth')               else writeln('Three-Body');         end else         begin           p:=0; q:=0;           q:=(n-m) div 2;           p:=(n-m+1) div 2;           if (q>=a[1]) or  ((q>=a[2]) and (not(odd(sum-a[2]-p-q))))              then writeln('Three-Body')              else if (p>=a[2]) and (odd(sum-a[2]-p-q))                      then writeln('Earth')                      else if p>q then writeln('Earth')                                  else writeln('Three-Body');         end;    end;    close(input); close(output);end.
原创粉丝点击