衡阳市八中day2修正版solution.docx
《衡阳市八中day2修正版solution.docx》由会员分享,可在线阅读,更多相关《衡阳市八中day2修正版solution.docx(14页珍藏版)》请在冰豆网上搜索。
![衡阳市八中day2修正版solution.docx](https://file1.bdocx.com/fileroot1/2023-2/21/a2244ecb-c8a8-457b-b8f3-caa63506ef05/a2244ecb-c8a8-457b-b8f3-caa63506ef051.gif)
衡阳市八中day2修正版solution
第一题
记得Mario64上有一个游戏,古代背景,点击一个格子就会使得它周围3x3范围内的格子翻动,要求在3步之内把格子翻成上面的图案。
此题类似,只不过是翻动本身和上下左右范围内的5个格,为怎样翻动才能翻成全为0的状态。
要求输出翻动方式(1是翻动,0是不翻动)且按字典序排列最靠前的那个。
首先注意字典序:
记住,越靠上及越靠右的格子字典顺序越靠前。
故第一个1越靠下,靠左最好。
本题的搜索不太容易想到。
如果直接暴搜,O(2^(n^2))的时间复杂度会算到地老天荒——所以观察,可以发现,如果第一行的翻动方式确定了,就可以唯一确定第二行的翻动方式。
原因是翻动过的第一行内,如果是1的格子,下面第二行必须翻动,第一行如果为0,下面第二行必须不翻动。
否则第一行的非0值就再也没有什么东西可以救它了。
于是时间复杂度直降O(2^n),可以搜索了。
无需剪枝,125MS可以接受。
第二题:
Thestartingpointhereisadynamicprogrammingalgorithm.Arbitrarilyrootthetreeandconsider"cuttingoff"aparticularsubtreeinasoldering.Thisleavesone(ornoneifawirewascutoffatitsendpoints)"cutwire"whichextendsoutofthesubtreetotheparentandasetofwiresthatarewhollywithinthesubtree.Now,notethatallthatisrelevantisthelengthofthe"cutwire"withinthesubtreeandthetotalcostofalltheotherwires.Thisisbecausethecutwireistheonlywirewhosecostdependsontherestofthesoldering.
Thisgivesarelativelysimpledynamicprogrammingsolution:
foreachvertex(definingasubtree)store,foreachpossiblecutwirelength,theminimumcostoftheotherwires;ifthereisnocutwirethiscanbetakenasawireoflength0.Wewillcomputethesefromthebottomup.Tocomputethesevalues,notethatifthereisacutwireitmustextenddowntooneofthechildren;thecostforacutwiregoingthroughaparticularchildisthecostforthecutwirethroughthechild'ssubtreeplustheminimumcostsolderingcoveringeachoftheothersubtrees.Ifthereisnocutwire,thentheedgegoingtotheparentmustbesolderedontothemiddleofanotherwire;thenonecanjustcheckallpairsoflengthsanddistinctchildrentofindtwo"cutwires"fortwochildrentomergeintointoonewire.Now,notethatthemaximumlengthcutwireforeachsubtreeisthenumberofnodesitcontains,sothenumberofpairsoflengthsforanytwodistinctchildrenisatmostthenumberofpairsofnodesinthetwochildren;summingoverallchildrenthisisthenumberofnodeswhoselowestcommonancestoristherootofthesubtree.Thenthetotalworkdoneoverthewholealgorithmisonlythetotalnumberofpairsofnodes,orO(N2).
Now,atthispointitwillbeconvenienttoassume,inthediscussionofthealgorithm,thateachvertexhasatmosttwochildren.Infact,thisisnotaproblem:
avertexVwithmorechildrencanbe"splitup"bygivingitadirectedgetooneofitschildrenandattachingtheremaindertoanewvertexV'withanedgetoitfromVoflength0(thelengthdoesnotbreakthealgorithmalthoughalledgesintheproblemwereoflength1),theniteratingthisuntilnovertexhasmorethantwochildren.
Tofurtherreducetheruntime,onemustnotetheconvexitypropertiesofthesquaringofthelength.Ifonelooksatalength/costpair(l,c)forasubtree,itcorrespondstothefunction(L+l)2+cwhereListhelengthofthecutwireoutsidethesubtree.ButoneonlycaresaboutthosefunctionsthataretheminimumforsomevalueofL:
since(L+l)2 +c=L2 +2L*l+(l2+c),thisisthelowerenvelopeofthesefunctions,equivalenttoaconvexhull.Allpairsnotintheenvelopecanbedeleted.Onecanthenbinarysearchtheconvexhulltofindtheoptimalpairingwithanyparticularlengthofthewireoutsidethesubtree.Thentofindtheoptimalpairoflengthsinthetwochildrentomergeintoonewire,onecansimplytakeallthelengthsinthesmallersubtreeandbinarysearchtheconvexhullinthelargersubtreetofindthebestthingwithinthatsubtreetopairitwith.Finally,toefficientlyfindtheconvexhullsforallsubtrees,onecanrepresenttheconvexhullswithbinarysearchtrees(std:
:
setdoesfinehere)andtogetthepossibilitiesfromeitherchild,onecanoffsetthevaluesinthelargerchildsubtree'sconvexhull(bystoringoffsetvaluesthatareaddedtoallthepairsinthehull,sincebothlengthandcostchangeasyoumergesubtrees)andtheninserteachpair(offset)fromthesmallersubtreeintoit.Thetotalnumberofoperationsonthebinarysearchtreesisthenatmostthesumofthesizesofthesmallerchildsubtreefromeachnode(infactitcanbesmallerastheconvexhullcanhavefewerelementsthanthesizeofthesubtree).ThiscanbeshowntobeO(NlogN):
onecanconsiderthenumberoftimeseachpositiongetsmergedintoalargergroup,andnotethatitisalwayslessthanlogNsincewitheachmergeonlythevaluesinthesmallerhalfareincremented.EachtreeoperationisO(logN),sotheoverallruntimeisO(Nlog2 N).
BelowisNealWu'sN2 implementation:
#include
#include
#include
usingnamespacestd;
FILE*in=fopen("solder.in","r"),*out=fopen("solder.out","w");
constintMAXN=50005;
constlonglongLLINF=1LL<<60;
intN,down[MAXN];
longlong*dp[MAXN],mindp[MAXN];
vectoradj[MAXN];
voidinit_dfs(intnum,intpar)
{
down[num]=1;
intpar_ind=-1;
for(inti=0;i<(int)adj[num].size();i++)
{
intchild=adj[num][i];
if(child==par)
{
par_ind=i;
continue;
}
init_dfs(child,num);
down[num]=max(down[num],down[child]+1);
}
if(par_ind!
=-1)
adj[num].erase(adj[num].begin()+par_ind);
}
voidsolve_dfs(intnum)
{
for(inti=0;i<(int)adj[num].size();i++)
solve_dfs(adj[num][i]);
longlongdp1=1;
if(adj[num].size()>1)
{
for(inti=0;i<(int)adj[num].size();i++)
dp1+=mindp[adj[num][i]];
longlongbest_two=LLINF;
for(inti=0;i<(int)adj[num].size();i++)
for(intj=i+1;j<(int)adj[num].size();j++)
{
intchild1=adj[num][i],child2=adj[num][j];
for(inta=1;a<=down[child1];a++)
for(intb=1;b<=down[child2];b++)
best_two=min(best_two,dp[child1][a]+dp
[child2][b]+2LL*a*b-mindp[child1]-mindp[child2]);
}
dp1+=best_two;
}
dp[num]=newlonglong[down[num]+1];
dp[num][1]=dp1;
if(adj[num].size()==1)
{
dp[num][1]=LLINF;
dp[num][0]=mindp[adj[num][0]];
}
else
dp[num][0]=dp[num][1]-1;
for(intk=1;k{
longlongsum=0,best_link=LLINF;
for(inti=0;i<(int)adj[num].size();i++)
{
intchild=adj[num][i];
sum+=mindp[child];
if(k<=down[child])
best_link=min(best_link,dp[child][k]-mindp[child]);
}
dp[num][k+1]=sum+best_link+2*k+1;
}
mindp[num]=LLINF;
for(intk=1;k<=down[num];k++)
mindp[num]=min(mindp[num],dp[num][k]);
for(inti=0;i<(int)adj[num].size();i++)
deletedp[adj[num][i]];
}
intmain()
{
fscanf(in,"%d",&N);
for(inti=1,a,b;i{
fscanf(in,"%d%d",&a,&b);a--;b--;
adj[a].push_back(b);
adj[b].push_back(a);
}
init_dfs(0,-1);
solve_dfs(0);
fprintf(out,"%lld\n",dp[0][0]);
return0;
}
AndbelowisMichaelCohen'simpressivefullimplementation:
#include
#include
#include
#defineendl'\n'
usingnamespacestd;
structposs{
longlongdepth;
longlongcost;
longlongtakeover;
booltcheck;
};
booloperator<(possa,possb){
if(a.tcheck||b.tcheck)return(a.takeoverif(a.depth>b.depth)returntrue;
if(a.depthreturn(a.cost}
intN;
vectoredges[50000];
boolvisited[50000];
longlongdepth[50000];
longlongoffset[50000];
set*best[50000];
voidrecurse(intnode){
visited[node]=true;
longlongbestPair=-1;
longlongallSoFar=0;
for(inti=0;iif(visited[edges[node][i]])continue;
depth[edges[node][i]]=depth[node]+1;
recurse(edges[node][i]);
longlongtadd;
{
posswhen={0,0,-depth[node],true};
set:
:
iteratorwhich=best[edges[node][i]]->upper_bound(when);
which--;
tadd=
(depth[node]-which->depth)*(depth[node]-which->depth)+which->cost+offset[edges[node][i]];
}
if(bestPair!
=-1)bestPair+=tadd;
if(best[node]==NULL){
best[node]=best[edges[node][i]];
offset[node]=offset[edges[node][i]];
}
else{
set*s=best[node],*t=best[edges[node][i]];
longlongos=offset[node]+tadd,ot=offset[edges[node][i]]+allSoFar;
if(s->size()size()){
set*tem=s;
s=t;
t=tem;
intto=os;
os=ot;
ot=to;
}
for(set:
:
iteratorit=t->begin();it!
=t->end();it++){
posswhen={0,0,it->depth-2*depth[node],true};
set:
:
iteratorwhich=s->upper_bound(when);
which--;
longlongthisPair=
(it->depth+which->depth-2*depth[node])*(it->depth+which->depth-2*depth[node])+it->cost+which->cost+offset[node]+offset[edges[node][i]];
if(bestPair==-1||thisPair}
for(set:
:
iteratorit=t->begin();it!
=t->end();it++){
possp=*it;
p.cost+=ot-os;
set:
:
iteratorwhere=s->insert(p).first;
boolkilled=false;
while(where!
=s->begin()){
set:
:
iteratorprev=where;
prev--;
if(prev->depth==where->depth){
s->erase(where);
killed=true;
break;
}
p.takeover=
(where->cost-prev->cost+where->depth*where->depth-prev->depth*prev->depth)/(2*prev->depth-2*where->depth);
while((2*prev->depth-2*where->depth)*p.takeover<
where->cost-prev->cost+where->depth*where->depth-prev->depth*prev->depth)
p.takeover++;
s->erase(where);
where=s->insert(p).first;
if(where->takeover<=prev->takeover)s->erase(prev);
elsebreak;
}
if(killed)continue;
if(where==s->begin()){
p.takeover=-1000000000;
s->erase(where);
where=s->insert(p).first;
}
set:
:
iter