17.8.14B组总结

来源:互联网 发布:python生成密码 编辑:程序博客网 时间:2024/05/16 15:59

17.8.14B组总结

T1

本来此题码量最小,可是我依然是最后改对的,O__O “…
其实也就是一个递推,设f[i]表示n个数最大公约数为i的方案数。显然,方案数中定会有算重的,减掉就好了。再设变量x=(r/i-(l-1)/i)(即为l~r中i的倍数的个数),f[i]即=x^n(没去重前总的方案数)-∑f[i*j] (j>=2;j<=(r-l+1)/i)(倍数的方案数)-x(选的数为同个数的方案数);至于需要注意的,有三点:

  1. l与r都先除以k(最大公约数就转为了1);
  2. 模数时加上1000000007(更改负数);
  3. 如l=1,则答案加1(全是1);
    Ps:最后连gcd都没有,看来还是要透过现象看本质。。。

T2

其实挺简单的,一听题解,秒懂。
通过满足F(Ai, Bi, Ci, Di) ≤ F(Ai+1, Bi+1, Ci+1, Di+1)可以看出,F函数是单调递增的,于是我们自然地想到了二分,每次找的区间[l,r],以及值(x)的取值范围a..b,每次递归记录答案即可,由于有log n层,每层m次,所以时间复杂度是O(m long n)。

T3

这题有各种各样的解法,但最终离不开一个中心——数位DP。
我用了最容易理解的一种,第一问就用dp(b)-dp(a)(dp(x)表示1~x中数字和为s的方案数);第二问与第一问差不多,将存的内容改为最小的数字即可;
贴段zys的题解

数位dp。
第一问:a~b的答案=1~b的答案-1~a-1的答案,只需计算1~x的答案即可。设f[i,j,0/1]表示前i位和为j,保证/不保证小于x。
当保证小于x时:下一位随便放
当不保证时:设x下一位数字为y,分两种情况
1:放0~y-1,可以保证小于
2:放y,不能保证小于
第二问:答案即不小于a的最小答案,与b无关。设f[i,j,0/1]表示前i位和为j,保证/不保证大于a。放法和第一问类似。

T4

考试想成线段树区间取模了,不会,只得打暴力~~
由于只有0..9 10个数,我们考虑对于每个数都开一棵线段树,加lazy标记(可合并地加),简单维护(某些人说要用两个数组,还要一堆复杂繁琐的过程,真搞不懂)就好了,这里贴一段修改与查询的代码(lc为lazy标记):
修改

procedure change(v,l,r,x,y:longint);var        mid,i:longint;        rc:array[0..9]of longint;begin        if (l=x)and(r=y) then        begin                rc:=f[v];                for i:=0 to 9 do                        f[v,(i+1) mod 10]:=rc[i];                inc(lc[v]);        end        else        begin                rc:=f[v*2];                for i:=0 to 9 do                        f[v*2,(i+lc[v]) mod 10]:=rc[i];                lc[v*2]:=lc[v]+lc[v*2];                rc:=f[v*2+1];                for i:=0 to 9 do                        f[v*2+1,(i+lc[v]) mod 10]:=rc[i];                lc[2*v+1]:=lc[2*v+1]+lc[v];                lc[v]:=0;                mid:=(l+r) div 2;                if y<=mid then                begin                        change(v*2,l,mid,x,y);                end                else                begin                        if x>mid then                                change(v*2+1,mid+1,r,x,y)                        else                        begin                                change(v*2,l,mid,x,mid);                                change(v*2+1,mid+1,r,mid+1,y);                        end;                end;                for i:=0 to 9 do                        f[v,i]:=f[v*2,i]+f[v*2+1,i];        end;end;

查询

procedure find(v,st,en,l,r:longint);var        mid,i:longint;        rc:array[0..9]of longint;begin        if (st=l)and(en=r) then        begin                for i:=0 to 9 do                        inc(s,i*f[v,i]);        end        else        begin                rc:=f[v*2];                for i:=0 to 9 do                        f[v*2,(i+lc[v]) mod 10]:=rc[i];                lc[v*2]:=lc[v]+lc[v*2];                rc:=f[v*2+1];                for i:=0 to 9 do                        f[v*2+1,(i+lc[v]) mod 10]:=rc[i];                lc[2*v+1]:=lc[2*v+1]+lc[v];                lc[v]:=0;                mid:=(st+en) div 2;                if (r<=mid) then                        find(v*2,st,mid,l,r)                else                        if (l>mid) then                                find(v*2+1,mid+1,en,l,r);                if (l<=mid)and(r>mid) then                begin                        find(v*2,st,mid,l,mid);                        find(v*2+1,mid+1,en,mid+1,r);                end;        end;end;

总的来说,改题主要还是心细,要有想法。

原创粉丝点击