NOIP2015模拟2

传送门

http://218.62.22.209:8080/problem.php?id=3172
http://218.62.22.209:8080/problem.php?id=3173
http://218.62.22.209:8080/problem.php?id=3174

T1 玛雅历

注意取模运算时的整除情况讨论

const
 t1:array[1..19]of string=('pop','no','zip','zotz','tzec','xul','yoxkin','mol','chen','yax','zac','ceh','mac','kankin','muan','pax','koyab','cumhu','uayet');
 t2:array[1..20]of string=('imix','ik','akbal','kan','chicchan','cimi','manik','lamat','muluk','ok','chuen','eb','ben','ix','mem','cib','caban','eznab','canac','ahau');
var
 a,b,aa,aaa:longint;
 n,ss:longint;
 i,j,k:longint;
 ans:array[0..18985,1..3]of longint;
 c,d:char;
 e,x:string;
 year,month,day,y1,y2:longint;

begin
 readln(n); writeln(n);
 for i:=1 to n do
  begin
   readln(e); ss:=pos('.',e);
   val(copy(e,1,ss-1),y1);
   e:=copy(e,ss+2,length(e)-ss-1);
   ss:=pos(' ',e);
   x:=copy(e,1,ss-1);
   val(copy(e,ss+1,length(e)-ss),y2);
   aaa:=y2*365+y1+1;
   for j:=1 to 19 do
    if t1[j]=x
    then begin aa:=j; break; end;
   inc(aaa,(aa-1)*20);
   if aaa mod 260=0
   then begin
    if aaa mod 260=0 then aaa:=(aaa div 260)-1 else aaa:=aaa div 260;
    writeln(13,' ',t2[20],' ',aaa);
   end
   else begin
    aa:=aaa mod 260; if aaa mod 260=0 then aaa:=(aaa div 260)-1 else aaa:=aaa div 260;
    if aa mod 13=0 then day:=13 else day:=aa mod 13;
    if aa mod 20=0 then month:=20 else month:=aa mod 20;
    writeln(day,' ',t2[month],' ',aaa);
   end;
  end;
end.

T2 密码

题目大意

给定一个密码B,在B的任意位置插入任意个数任意小写字符,得到加密后的字符串A,对A进行切割,切割方式为从前向后切任意个,从后也是,是切割后剩余部分仍保留包含B的完整信息

题解

为了不重复,我们枚举从开头删的个数0..length(B),举个例子
abcdabcabc
abc
(0,0..6) (1..4,0..3) (5..7,0)
也就是说我们先处理出A在B中的每个最紧凑的存在位置,对于相邻的两个,他们的起始位置和终止位置分别为L[i],R[i],L[i+1],R[i+1],我们可以发现,从头删到L[i]..L[i+1]-1,这(L[i+1]-L[i])种情况删除后面的方法是一致的,即(0..length(B)-R[i+1]+1),所以相邻的两个对于ans的贡献为(L[i+1]-L[i])*(0..length(B)-R[i+1]+1)

var
 x:array[0..300000,1..2]of longint;
 y:array[0..300000,1..26]of longint;
 i,j,k:longint;
 n,m:longint;
 a,b:ansistring;
 tt,len:longint;
 ans,c,d:int64;
function f(i,j:longint):longint;
begin
 if i<=0 then exit(-1);
 if j=1 then exit(i);
 f:=f(y[i,ord(b[j-1])-96],j-1);
end;

begin
 readln(a); readln(b);
 n:=length(a); m:=length(b);
 for i:=2 to n do
  begin
   for j:=1 to 26 do
    if ord(a[i-1])-96=j
    then y[i,j]:=i-1
    else y[i,j]:=y[i-1,j];
   if a[i]=b[m]
   then tt:=f(i,m);
   if tt<>-1 then begin inc(len); x[len,1]:=tt; x[len,2]:=i; end;
  end;
 ans:=0;
 for i:=1 to len do
  begin
   c:=x[i,1]-x[i-1,1];
   d:=n-x[i,2]+1;
   inc(ans,c*d);
  end;
 writeln(ans);
end.

T3 独立集

题目大意

给定一串数字,用冒泡排序简图,找最大独立集,及一定在队立即内的数(好吧,你看不懂很正常……直接转去题目看好了…)

题解

经过分析后我们发现,其实是求这段数的LIS,及一定会在LIS内的数是那些,100000要写 nlogn 的LIS
正着扫一遍最长上升,倒着扫一遍最长下降,每个数的两个值加起来若为ans-1则在LIS内,
然后我们把不是的删掉,再做一遍LIS,如果LIS第i位不唯一,那么所有可以作为第i位的数都不一定在LIS中

const
 maxn=100000;
var
 sum,y,z,w,f,g,x:array[0..maxn]of longint;
 i,j,k:longint;
 ans,anss,tt,n:longint;
function find(a,b:longint):longint;
var l,r,mid:longint;
begin
 l:=1; r:=ans;
 while l<r do
  begin
   mid:=(l+r)>>1;
   if b=1
   then begin
    if y[mid]>a
    then r:=mid else l:=mid+1;
   end
   else begin
    if z[mid]>a
    then l:=mid+1 else r:=mid;
   end;
  end;
 exit(l);
end;

begin
 readln(n);
 for i:=1 to n do
  read(x[i]);
 fillchar(y,sizeof(y),0);
 y[1]:=x[1]; ans:=1; f[x[1]]:=1;
 for i:=2 to n do
  begin
   if y[ans]<x[i]
   then begin
    inc(ans); y[ans]:=x[i]; f[x[i]]:=ans;
   end
   else begin
    tt:=find(x[i],1); y[tt]:=x[i]; f[x[i]]:=tt;
   end;
  end;
 writeln(ans); anss:=ans;
 fillchar(z,sizeof(z),0);
 z[1]:=x[n]; ans:=1; g[x[n]]:=1;
 for i:=n-1 downto 1 do
  begin
   if z[ans]>x[i]
   then begin
    inc(ans); z[ans]:=x[i]; g[x[i]]:=ans;
   end
   else begin
    tt:=find(x[i],2); z[tt]:=x[i]; g[x[i]]:=tt;
   end;
  end;
 x[0]:=0;
 for i:=1 to n do
  if (g[x[i]]+f[x[i]]=anss+1)
  then begin inc(x[0]); x[x[0]]:=x[i]; z[x[0]]:=i; end;
 fillchar(y,sizeof(y),0);
 y[1]:=x[1]; ans:=1; f[x[1]]:=1;
 for i:=2 to x[0] do
  begin
   if y[ans]<x[i]
   then begin
    inc(ans); y[ans]:=x[i]; f[x[i]]:=ans;
   end
   else begin
    tt:=find(x[i],1); y[tt]:=x[i]; f[x[i]]:=tt;
   end;
  end;
  for i:=1 to x[0] do
  inc(sum[f[x[i]]]);
 if ans<>anss then writeln('!');
 for i:=1 to x[0] do
  if sum[f[x[i]]]=1
  then begin inc(w[0]); w[w[0]]:=i; end;
 for i:=1 to w[0]-1 do
  write(z[w[i]],' ');
 writeln(z[w[w[0]]]);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值