题目及题解可以参见BYV大牛的,很详细
http://www.byvoid.com/blog/noi-2008-design/
自己的一些想法:
实现的时候不需要求第一问的解是多少,只需要找到第一个a[i,b]>0的b,然后前面的a[i,b1] b1<b都是等于0的。所以这个定义<=b的方案数就是=b的方案数。
要熟悉这种利用辅助递推,前缀乘积,后缀乘积,以及固定一个指针,划另外一个为1维的题。
至于不超过10,要大胆猜测,就路径剖分来说,路径上的轻边不超过log2n条,至于这个题的特殊性,答案为log3n。
一个优化:可以迭代b,暂时不管>b的东西。因为b涉及到的只有b和b-1,找到一个了就输出。
离NOI还有距离,努力!
program xqz; const maxn=100001; type rec=record x,y:longint; end; var i,j,k,m,n,mo,ss,tt,e,ans:longint; edge,point,next:array[0..2*maxn] of longint; f,g,a:array[0..maxn,-1..11] of rec; c,sf,pf:array[0..maxn] of rec; z,q:array[0..maxn] of longint; yi,ling:rec; operator +(a,b:rec)c:rec; begin c.y:=a.y or b.y; c.x:=(a.x+b.x) mod mo; end; operator *(a,b:rec)c:rec; begin c.y:=a.y and b.y; c.x:=(int64(a.x)*b.x) mod mo; end; procedure dfs1(i,fa:longint); var b,p:longint; begin z[i]:=fa; b:=edge[i]; while b<>0 do begin p:=point[b]; if z[p]=0 then dfs1(p,i); b:=next[b]; end; b:=edge[i]; m:=0; while b<>0 do begin p:=point[b]; if z[p]=i then begin inc(m); q[m]:=p; end; b:=next[b]; end; for b:=0 to 10 do begin sf[m+1]:=yi; pf[0]:=yi; for j:=1 to m do pf[j]:=pf[j-1]*a[q[j],b-1]; for j:=m downto 1 do sf[j]:=sf[j+1]*a[q[j],b-1]; if m>=2 then begin c[m+1]:=ling; for j:=m downto 1 do begin c[j]:=c[j+1]*a[q[j],b-1]+g[q[j],b]*sf[j+1]; f[i,b]:=f[i,b]+pf[j-1]*g[q[j],b]*c[j+1]; end; end; if m>=1 then begin for j:=1 to m do g[i,b]:=g[i,b]+g[q[j],b]*pf[j-1]*sf[j+1]; g[i,b]:=g[i,b]+pf[m]; end else g[i,b]:=yi; a[i,b]:=g[i,b]+f[i,b]; end; end; begin assign(input,'design.in'); reset(input); assign(output,'design.out'); rewrite(output); read(n,m,mo); if m<>n-1 then begin writeln(-1); writeln(-1); end else begin for i:=1 to m do begin read(ss,tt); inc(e); point[e]:=tt; next[e]:=edge[ss]; edge[ss]:=e; inc(e); point[e]:=ss; next[e]:=edge[tt]; edge[tt]:=e; end; yi.x:=1; yi.y:=1; ling.x:=0; ling.y:=0; dfs1(1,1); for i:=0 to 10 do if a[1,i].y=1 then begin writeln(i); writeln(a[1,i].x); break; end; end; close(input); close(output); end.