只做了第一题,得分100,有29人得分超过100,zzm140分,只有14个人比他高。这次比赛难度应该是比较大,应该把暴力写好,第三题30分还是比较好拿。第一题写的时间太长了。
A 进制转换
小数转分数是百度搜的规律,应该多想一会。这题耽误很长时间,一直在纠结分数转二进制的时候哪个句子在哪个句子前边。还是思路不清楚的缘故。
还有两个很好的思路。
官方题解:不难发现,我们列方程的方法是将X的小数点向右移动若干位,移出两个正好错开了循环节长度为的小数,此时两个数相减,可以将循环部分消除,便可以解出方程。一般地,假设有p1位非循环位,非循环部分形成的十进制数是k1;有p2位循环节,循环节部分形成的十进制数是k2。
可以得到方程:10^(p1+p2)*X-(10^p1)*X=(10^p2)k1+k2-k1。
比较暴力的做法:直接模拟性价比较高,将十进制的循环部分扩增到1000位
然后不断*2,hash判重。
Codeprogram vijos1062A;
var i,a,b,c,t,cnta,tot,ans:longint;
pos:array[0..1000000] of longint;
s:array[0..1000000] of longint;
ch:char;
function GCD(a,b:longint):longint;
var r:longint;
begin
repeat
r:=a mod b;
a:=b;b:=r;
until r=0;
exit(a);
end;
begin
read(ch);read(ch);read(ch);
while ch<>'(' do begin
a:=a*10+ord(ch)-ord('0');
inc(cnta);read(ch);end;
read(ch);b:=a;
while ch<>')' do begin
b:=b*10+ord(ch)-ord('0');
c:=c*10+9;
read(ch);end;
for i:=1 to cnta do c:=c<<1+c<<3;
b:=b-a;t:=gcd(b,c);
b:=b div t;c:=c div t;
tot:=0;ans:=0;tot:=0;
//writeln(b,'/',c);
while pos[b]=0 do begin
inc(tot);pos[b]:=tot;b:=b<<1;ans:=0;
if b>=c then begin
dec(b,c);
ans:=1;
end;
s[tot]:=ans;
end;
write('0.');
for i:=1 to pos[b]-1 do write(s[i]);
write('(');
for i:=pos[b] to tot do write(s[i]);
writeln(')');
//for i:=1 to tot do writeln(s[i]:5,pos[i]:5);
end.
orzsjx的神模拟
Code
program T1062_1;
var s:string;
n,m,i,j,k,mo,moo:longint;
dn,dm,rec:array[0..1000000]of longint;
begin
readln(s);write('0.');
k:=pos('(',s);
mo:=1;moo:=1;
for i:=3 to k-1 do mo:=mo*10;
for i:=k+1 to length(s)-1 do moo:=moo*10;
if k>3 then val(copy(s,3,k-3),n,i);
val(copy(s,k+1,length(s)-k-1),m,i);
rec[0]:=0;
dn[0]:=n;
dm[0]:=m;
if k>3 then
begin
for i:=1 to 1000000 do
begin
rec[i]:=dn[i-1]*2 div mo;
dn[i]:=dn[i-1]*2 mod mo+dm[i-1]*2 div moo;
dm[i]:=dm[i-1]*2 mod moo+dm[i-1]*2 div moo;
for j:=0 to i do if (dn[i]=dn[j])and(dm[i]=dm[j]) then break;
if j<>i then
begin
for k:=1 to j do write(rec[k]);
write('(');
for k:=j+1 to i do write(rec[k]);
writeln(')');
writeln;
for k:=0 to i do
writeln(rec[k]:5,dn[k]:5,dm[k]:5);
halt;
end;
end;
end else
begin
for i:=1 to 1000000 do
begin
rec[i]:=dm[i-1]*2 div moo;
dm[i]:=dm[i-1]*2 div moo+dm[i-1]*2 mod moo;
for j:=0 to i do if dm[i]=dm[j] then break;
if i<>j then
begin
for k:=1 to j do write(rec[k]);
write('(');
for k:=j+1 to i do write(rec[k]);
write(')');
halt;
end;
end;
end;
end.
B 时区
好神奇的题目,看了题解以后做的。发现一个人的时区确定了以后他前面的人的时区就有了上界,后面类似,每次找可选时区最少的搜索。
Code
VijosNT Mini 2.0.5.7 Special for Vijos
编译通过...
├ 测试数据 01:答案正确... (0ms, 700KB)
├ 测试数据 02:答案正确... (0ms, 700KB)
├ 测试数据 03:答案正确... (0ms, 700KB)
├ 测试数据 04:运行超时... (?, 700KB)
├ 测试数据 05:答案正确... (0ms, 700KB)
├ 测试数据 06:答案正确... (0ms, 700KB)
├ 测试数据 07:答案正确... (0ms, 700KB)
├ 测试数据 08:答案正确... (0ms, 700KB)
├ 测试数据 09:答案正确... (0ms, 700KB)
├ 测试数据 10:答案正确... (0ms, 700KB)
program vijos1749;
uses math;
const FileName='vijos1749';maxn=60;
var ans,t:array[0..maxn] of longint;
a,n,i:longint;
function upint(a,b:longint):longint;
begin
if a<=0 then exit(0)
else exit((a-1)div b+1);
end;
procedure print;
var i:longint;
begin
for i:=1 to n-1 do
write(ans[i],' ');
writeln(ans[n]);
halt;
end;
procedure DFS(k:longint;sq,ren:int64);
var i,r,l,cnt,find:longint;
begin
if k>n then print;cnt:=n+1;
for i:=1 to n do
if(not boolean((ren>>i)and 1))
then begin
l:=i;r:=i;
while( l>0 )and(not boolean((ren>>l)and 1))do dec(l);
while(r<n+1)and(not boolean((ren>>r)and 1))do inc(r);
if l<>0 then l:=upint((ans[l]*60+t[l]-t[i]),60)else l:=0;
if r<>n+1 then r:= (ans[r]*60+t[r]-t[i])div 60 else r:=n-1;
if(r<0)or(l>n-1)or(l>r)then continue;
if min(r,n-1)-max(l,0)+1<cnt
then begin
cnt:=min(r,n-1)-max(l,0)+1;
find:=i;end;
end;
l:=find;r:=find;if k=1 then find:=n>>1;if cnt=n+1 then exit;
while( l>0 )and(not boolean((ren>>l)and 1))do dec(l);
while(r<n+1)and(not boolean((ren>>r)and 1))do inc(r);
if l>0 then l:=upint((ans[l]*60+t[l]-t[find]),60)else l:=0;
if r<n+1 then r:=(ans[r]*60+t[r]-t[find]) div 60 else r:=n-1;
//writeln(k:5,l:5,r:5,find:5,sq:5,ren:5);
for i:=min(r,n-1) downto max(l,0) do
if(not boolean((sq>>i)and 1))and(i*60+t[find]<(n-1)*60+59)
then begin
ans[find]:=i;
DFS(k+1,sq or(int64(1)<<i),ren or(int64(1)<<find));
end;
end;
begin
readln(n);
for i:=1 to n do
begin
readln(a);
t[i]:=a mod 100+(a div 100)*60
end;
DFS(1,0,0);
end.
C 建房子
把每一个可能建房屋的左上角作为处理的对象是很重要的一个想法。然后利用单调队列和前缀和可以再平方的复杂度里算出所有的代价。然后用一个双向链表维护可建造的点,暴力删除。
Codeprogram vijos1750;
uses math;
const maxn=1000;FileName='vijos1750';
type Tqueue=record
h,t:longint;
QA,QB:array[0..maxn]of longint;
end;
var Q:array[1..maxn] of TQueue;
f:array[1..maxn] of longint;
sum:array[0..maxn,0..maxn] of int64;
pos,height:array[0..maxn,0..maxn] of longint;
cost:array[0..maxn*maxn]of int64;
x,y,pre,next:array[0..maxn*maxn] of longint;
//forbid:array[1..maxn*maxn] of boolean;
nx,ny,i,j,n,m,a,b,tot,s:longint;
tmp:TQueue;
function cmp(i,j:longint):boolean;
begin
if cost[i]<cost[j] then exit(true);
if cost[i]>cost[j] then exit(false);
if x[i]<x[j] then exit(true);
if x[i]>x[j] then exit(false);
if y[i]<y[j] then exit(true);
if y[i]>=y[j] then exit(false);
end;
procedure swap(var x,y:int64);
var t:int64;
begin t:=x;x:=y;y:=t;end;
procedure swap(var x,y:longint);
var t:longint;
begin t:=x;x:=y;y:=t;end;
procedure Qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l;j:=r;mid:=(l+r)>>1;
x[0]:=x[mid];y[0]:=y[mid];cost[0]:=cost[mid];
repeat
while(i<r)and cmp(i,0)do inc(i);
while(l<j)and cmp(0,j)do dec(j);
if i<=j then begin
swap(cost[i],cost[j]);
swap(x[i],x[j]);
swap(y[i],y[j]);
inc(i);dec(j);
end;
until i>j;
if(l<j)then Qsort(l,j);
if(i<r)then Qsort(i,r);
end;
procedure init(var Q:TQueue);
begin Q.h:=1;Q.t:=0;end;
function Getmin(var Q:TQueue;x:longint):longint;
begin
with Q do begin
while(h<=t)and(QA[h]>x)do inc(h);
exit(QB[h]);end;
end;
procedure ADD(var Q:TQueue;x,y:longint);
begin
with Q do begin
while(h<=t)and(QB[t]>=y)do dec(t);
inc(t);QA[t]:=x;QB[t]:=y;end;
end;
function calc(a,b,c,d:longint):int64;
begin exit(sum[c][d]-sum[a-1][d]-
sum[c][b-1]+sum[a-1][b-1]);end;
begin
readln(n,m,a,b);
//==getsum==
for i:=1 to n do
for j:=1 to m do
begin
read(height[i][j]);
sum[i][j]:=sum[i-1][j]+sum[i][j-1]
-sum[i-1][j-1]+height[i][j];
end;
//==init the Queue==
for i:=1 to n do
begin init(Q[i]);
for j:=m downto m-b+2 do
ADD(Q[i],j,height[i][j]);
end;
//==getminnum==
for j:=m-b+1 downto 1 do
begin//处理第j列
for i:=1 to n do begin//更新每一列最小值
ADD(Q[i],j,height[i][j]);
F[i]:=Getmin(Q[i],j+b-1);
end;
init(tmp);//初始化队列
for i:=n downto n-a+2 do
ADD(tmp,i,F[i]);
for i:=n-a+1 downto 1 do//开始算
begin inc(tot);
ADD(tmp,i,F[i]);
cost[tot]:=Getmin(tmp,i+a-1);
x[tot]:=i;y[tot]:=j;end;
end;
//===getcost===
for i:=1 to tot do
cost[i]:=calc(x[i],y[i],x[i]+a-1,y[i]+b-1)-a*b*cost[i];
Qsort(1,tot);
for i:=1 to tot do
begin
pos[x[i]][y[i]]:=i;
pre[i]:=i-1;
next[i]:=i+1;
end;
pre[1]:=0;next[tot]:=0;i:=1;
//==build==
while i<>0 do begin
inc(s);pos[x[i]][y[i]]:=0;//没有这句会删掉自己
for nx:=max(x[i]-a+1,1) to min(x[i]+a-1,n)do
for ny:=max(y[i]-b+1,1) to min(y[i]+b-1,m)do
if pos[nx][ny]<>0
then begin
j:=pos[nx][ny];
next[pre[j]]:=next[j];
pre[next[j]]:=pre[j];
pos[nx][ny]:=0;end;
i:=next[i];end;
//==output==
writeln(S);i:=1;
while i<>0 do begin
writeln(x[i],' ',y[i],' ',cost[i]);
i:=next[i];end;
end.
转载于:https://www.cnblogs.com/lijianlin1995/archive/2012/10/29/2744761.html