XJOI NOIP模拟题2

第一题

组合计数

分析:

从前往后一位一位的计算

先算第一位比t小的数目,再算第一位与t[1]相同,第2位比t小的个数以此类推

先预处理一个数组h,h[i]表示从1~it串与s串不同的位数

对于第i位,

由于1~i-1与s串一样,故i~n中与s串不同的个数有k-h[i-1]个,设v=k-h[i-1]。

F(i)表示’a'到t[i]中与s[i]不相同字母个数(不包括t[i]),

当s[i]>=t[i]则

第i位开始比t小的数目ANS[i]=F(i)*C(n-i,v-1)*(25)^(v-1)

当s[i]<t[i]则

第i位开始比t小的数目ANS[i]=[F(i)-1]*C(n-i,v-1)*(25)^(v-1) +C(n-i,v)*25^v

输出∑ANS[i]+1即可。

代码:

program t1;
const
  num=1000000007;
var
  a,b:array[0..100001]of char;
  d,h,f,g:array[0..100001]of int64;
  n,m,v,len,x,y,ans:int64;  i:longint;
function get(x,y:int64):int64;
var i:longint; t:int64;
begin
  if (x=0)or(y=0)or(x=y) then exit(1);
  exit(((f[x]*g[x-y]) mod num)*g[y] mod num);
end;
function quick(x,y:int64):int64;
var ans:int64;
begin
  ans:=1;
  while y>0 do
  begin
    if y and 1>0 then ans:=ans*x mod num;
    x:=x*x mod num;
    y:=y>>1;
  end;
  exit(ans);
end;
procedure make;
var i:longint;
begin
  f[0]:=1; g[0]:=1;
  for i:=1 to n do
   begin
     f[i]:=(f[i-1]*i) mod num;
     g[i]:=g[i-1]*quick(i,num-2) mod num;
   end;
end;
begin
  readln(n,m);
  d[0]:=1;  ans:=0;
  for i:=1 to m do d[i]:=(d[i-1]*25) mod num;
  for i:=1 to n do read(a[i]);  readln;
  for i:=1 to n do read(b[i]);
  for i:=1 to n do if a[i]<>b[i] then h[i]:=h[i-1]+1 else h[i]:=h[i-1];
  for i:=n downto 1 do h[i]:=m-h[i-1];
  make;
  for i:=1 to n do
   begin
     if a[i]<b[i] then len:=ord(b[i])-ord('a')-1
      else len:=ord(b[i])-ord('a');
     v:=h[i]; if v=0 then break;
     y:=get(n-i,v-1); ans:=ans+((d[v-1]*y)mod num*len) mod num;
     if (a[i]<b[i])and(n-i>=v) then begin  x:=get(n-i,v);  ans:=(ans+d[v]*x) mod num; end;
   end;
  writeln((ans+1)mod num);
end.
View Code

 

第二题

 

第三题

树型DP

分析:

最容易想到的O(n*m*m)的DP,用f[i,j]表示以i为根子树选j个的最大价值,f[i,j]=∑f[k,w[k]] w[k]表示k节点选取的点数,显然这是一个背包

然而这样的效率是不够的。

可以改变思路

posted @ 2016-11-13 18:52  QTY_YTQ  阅读(260)  评论(0编辑  收藏  举报