被催着做了Test 09-Day1..
嗯那我就写一下题解了。。
1. 词编码(word.pas/c/cpp)
【问题描述】
一个发送机可以通过一条隧道发送一些以二进制代码组成的单词。在其尽头的接受机可以使用特殊技术恢复到最初的单词。每个单词最初都由0和1组成。所有的单词最初长度都为n(4<=n<=1000)。当穿过隧道之后单词可能发生以下几种情况之一:
(1)任意(一个)0被1取代;
(2)任意(一个)符号被删除;
(3)一个符号(0或1)被插入到任何位置;
(4)不改变。
我们知道最初的单词都具有以下性质:有1的位置号的总和是n+1的倍数,或者是0。
【输入】
n和转换后的单词,每个单词占一行。单词数不大于2001,不会有其他任何东西,除了空格和空行。
【输出】你的程序应该打印输出原始序列的词,注意换行。若有多解,操作4有限,不行则按操作1、2、3优先。同一操作,按操作位置最先的优先(从左到右数起1、2、3…n)。对于操作2,先在被删数列添0,不行再添1。如果没有答案则输出-1。
码农题。。
刚开始没看到原来长度是n被坑了一把。。
const shuru='word.in';
shuchu='word.out';
var s:array[0..1001] of char;
count,tot,len,i,j,k,n:longint;
a,d:array[0..1001] of longint;
sign:boolean;
procedure setIO;
begin
assign(input,shuru);reset(input);
assign(output,shuchu);rewrite(output);
readln(n);
end;
procedure closeIO;
begin
close(input); close(output);
end;
procedure main;
begin
setIO;
while not(eof) do
begin
tot:=0; len:=0; count:=0;
a[0]:=0; sign:=false;
while not(eoln) do
begin
inc(len);
read(s[len]);
if s[len]='1' then begin
inc(tot,len);
inc(count);
d[count]:=len;
a[len]:=a[len-1]+1
end
else a[len]:=a[len-1];
end;
readln;
if len=n then begin
if tot mod (len+1)=0 then begin
for k:=1 to len do write(s[k]);
writeln;
continue;
end;
for i:=1 to count do
if (tot-d[i]) mod (len+1)=0 then begin
for k:=1 to d[i]-1 do write(s[k]);
write(0);
for k:=d[i]+1 to len do write(s[k]);
writeln;
sign:=true;
break;
end;
if sign then continue;
writeln(-1);
continue;
end;
if len=n-1 then begin
for i:=1 to len do
if (tot+a[len]-a[i-1]) mod (len+2)=0 then begin
for k:=1 to i-1 do write(s[k]);
write(0);
for k:=i to len do write(s[k]);
writeln;
sign:=true;
break;
end;
if sign then continue;
if tot mod (len+2)=0 then begin
for k:=1 to len do write(s[k]);
writeln(0);
continue;
end;
for i:=1 to len do
if (tot+a[len]-a[i-1]+i) mod (len+2)=0 then begin
for k:=1 to i-1 do write(s[k]);
write(1);
for k:=i to len do write(s[k]);
writeln;
sign:=true;
break;
end;
if sign then continue;
if (tot+len+1) mod (len+2)=0 then begin
for k:=1 to len do write(s[k]);
writeln(1);
continue;
end;
writeln(-1);
continue;
end;
for i:=1 to len do
case s[i] of
'0':if (tot-(a[len]-a[i])) mod len=0 then begin
for k:=1 to i-1 do write(s[k]);
for k:=i+1 to len do write(s[k]);
writeln;
sign:=true;
break;
end;
'1':if (tot-i-(a[len]-a[i])) mod len=0 then begin
for k:=1 to i-1 do write(s[k]);
for k:=i+1 to len do write(s[k]);
writeln;
sign:=true;
break;
end;
end;
if not(sign) then writeln(-1);
end;
end;
begin
main;
end.
T2
2. 笨笨粉刷匠(draw.pas/c/cpp)
【问题描述】
笨笨太好玩了,农田荒芜了,彩奖用光了,笨笨只好到处找工作,笨笨找到了一份粉刷匠的工作。
笨笨有n 条木板需要被粉刷。每条木板被分成m 个格子,每个格子要被刷成红色或蓝色。笨笨每次粉
刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色,已知每个格子最多只能被粉刷一次。
如果笨笨只能粉刷t 次,他最多能正确粉刷多少格子。
一个格子如果未被粉刷或被粉刷成错误颜色,就算粉刷错误。
【输入】
第一行三个数n,m,t;
接下来n 行,每行一个长度为m 的字符“0”表示红色,"1"表示蓝色。
【输出】
一个整数,最多能正确粉刷的格子数。
看到题的时候在猜。。猜是DP还是贪心。。
不过觉得贪心不大可能,就想是DP
然后想到了某一行涂k次的DP转移方程。。
设f[i,j]表示前i个涂j次最多能涂对多少个。
f[i,j]:=max(f[i-1,j],f[k,j]+best[k+1,i]){其中best[k+1,j]表示从k+1到j 0和1个数中较大的那个。。
然后发现不会合并。。。
想了很久。。
后来很弃疗地看了lzw大神的博客。。
发现是背包233333.
以后这种资源分配的需要合并用背包。。
也算是学到了一点东西吧。。
Code:
const shuru='draw.in';
shuchu='draw.out';
maxn=51;
maxt=2501;
var f:array[0..maxn,0..maxt] of longint;
a:array[0..maxn,0..maxn] of char;
p,q:array[0..maxn,0..maxn] of longint;
v:array[0..maxn,0..maxn] of longint;
ans:array[0..maxt] of longint;
pp,step,l,i,j,k,n,m,t:longint;
function min(a,b:longint):longint;
begin
if a<b then exit(a);
exit(b);
end;
procedure init;
begin
assign(input,shuru);reset(input);
assign(output,shuchu);rewrite(output);
readln(n,m,t);
if n*m=t then begin
writeln(t);
close(input);close(output);
halt;
end;
for i:=1 to n do
begin
for j:=1 to m do
read(a[i,j]);
readln;
end;
end;
function max(a,b:longint):longint;
begin
if a>b then exit(a);
exit(b);
end;
procedure main;
begin
init;
step:=min(m,t);
for k:=1 to n do
begin
fillchar(p,sizeof(p),0);
fillchar(q,sizeof(q),0);
for i:=1 to m do
for j:=i to m do
if a[k,j]='1' then begin
p[i,j]:=p[i,j-1]+1;
q[i,j]:=q[i,j-1];
end
else begin
p[i,j]:=p[i,j-1];
q[i,j]:=q[i,j-1]+1;
end;
for i:=1 to m do
for l:=1 to step do
begin
f[i,l]:=f[i-1,l];
for j:=0 to i-1 do
f[i,l]:=max(f[i,l],f[j,l-1]+max(p[j+1,i],q[j+1,i]));
end;
for i:=0 to step do
v[k,i]:=f[m,i];
end;
for k:=1 to n do
for j:=t downto 0 do
begin
pp:=min(j,step);
for i:=0 to pp do
ans[j]:=max(ans[j],ans[j-i]+v[k,i]);
end;
writeln(ans[t]);
close(output); close(input);
end;
begin
main;
end.
3. 笨笨的电话网络(phone.pas/c/cpp)
【问题描述】
多年以后,笨笨长大了,成为了电话线布置师。由于地震使得某市的电话线全部损坏,笨笨是负责将电话线接到该市的负责人。该市周围分布着N(1≤N≤1000)根按1..N顺次编号的废弃的电话线杆,任意两根电话线杆间都没有电话线相连。一共P(1≤P≤10000)对电话线杆间可以拉电话线,其余的由于地震使得无法被连接。
第i对电话线杆的两个端点分别为Ai,Bi,它们间的距离为Li(1≤Li≤1000000)。数据保证每对(Ai,Bi)最多只出现1次。编号为1的电话线杆已经接入了全国的电话网络,整个市的电话线全都连到了编号为N的电话线杆上。也就是说,笨笨的任务仅仅是找一条将1号和N号电话线杆连起来的路径,其余电话线杆并不一定要连入电话网络。
电信公司决定支援灾区免费为该市连接K(0≤K≤N)对由笨笨指定的电话线杆。对于此外的那些电话线,需要为它们付费,总费用等于其中最长的电话线的长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线杆不超过K对,那么总支出为0。
笨笨需要计算一下,将电话线引到震中市最少需要在电话线上花多少钱?
【输入】
输入文件的第一行包含三个用空格隔开的整数:N,P和K。
第二行到第P+1行:每行分别都为三个用空格隔开的整数:Ai,Bi和Li。
【输出】输出文件中仅包含一个整数,表示在这项工程上的最小支出。如果任务不可能完成,则输出-1。
这题是某一天早上模模糊糊想出来的。。
很明显就是找这样一条路,使它的第k+1大的边最小
这种什么xxx的最小肯定用二分答案,转化成判定问题
二分答案后,对所有的边,如果它大于他,就是1,否则就是0.
然后做最短路,如果小于等于k,就可以的。。
最开始数组开小只拿了30分真是开心。。
const shuru='phone.in';
shuchu='phone.out';
maxn=1001;
maxm=20002;
INF=1 shl 26;
long=40*maxn;
var d,headlist:array[0..maxn] of longint;
weight,w,t,next:Array[0..maxm] of longint;
queue:array[0..long] of longint;
inq:Array[0..maxn] of boolean;
a:Array[0..maxm] of longint;
l,r,mid,ans,data,front,finish,p,i,j,k,n,m,x,y,z,num:longint;
procedure init;
begin
assign(input,shuru);reset(input);
assign(output,shuchu);rewrite(output);
readln(n,m,k);
for i:=1 to n do headlist[i]:=-1;
for i:=1 to m do
begin
readln(x,y,z);
a[i]:=z;
inc(num);
next[num]:=headlist[x];
headlist[x]:=num;
t[num]:=y;
weight[num]:=z;
inc(Num);
next[num]:=headlist[y];
headlist[y]:=num;
t[num]:=x;
weight[num]:=z;
end;
close(input);
end;
procedure qsort(left,right:longint);
var i,j,mid:longint;
begin
i:=left; j:=right; mid:=a[(i+j) shr 1];
repeat
while a[i]<mid do inc(i);
while a[j]>mid do dec(j);
if i<=j then begin
p:=a[i];
a[i]:=a[j];
a[j]:=p;
inc(i);
dec(j);
end;
until i>j;
if j>left then qsort(left,j);
if i<right then qsort(i,right);
end;
function spfa(sign:longint):longint;
var i:longint;
begin
w:=weight;
for i:=1 to num do if w[i]>sign then w[i]:=1 else w[i]:=0;
fillchar(inq,sizeof(inq),false);
for i:=1 to n do d[i]:=INF;
d[1]:=0;
queue[1]:=1; inq[1]:=true;
front:=0; finish:=1;
while front<>finish do
begin
inc(front);
if front>long then front:=front-long;
x:=queue[front];
i:=headlist[x];
inq[x]:=false;
while i<>-1 do
begin
if d[t[i]]>d[x]+w[i] then begin
d[t[i]]:=d[x]+w[i];
if not(inq[t[i]]) then begin
inc(finish);
if finish>long then finish:=finish-long;
queue[finish]:=t[i];
inq[t[i]]:=true;
end;
end;
i:=next[i];
end;
end;
exit(d[n]);
end;
function min(a,b:longint):longint;
begin
if a<b then exit(a);
exit(b);
end;
procedure main;
begin
init;
data:=spfa(-1);
if data<=k then begin
writeln(0);
close(output);
halt;
end;
if d[n]=INF then begin
writeln(-1);
close(output);
halt;
end;
qsort(1,m);
l:=1; r:=m; ans:=INF;
repeat
mid:=(l+r) shr 1;
data:=spfa(a[mid]);
if data<=k then begin
ans:=min(ans,a[mid]);
r:=mid-1;
end
else l:=mid+1;
until l>r;
writeln(ans);
close(output);
end;
begin
main;
end.