被催着做了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.