zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 81 (Div. 2) 题解 1295A 1295B 1295C 1295D 1295E 1295F

    A

    输出111111111...或711111111...即可

    B

    多一个0,就+1;多一个1,就-1。

    记录每一位的前缀和,前面每重复一次字符串s,就相当于整体加几或者减几。因此就是模运算判断一下就好。不能理解的话可以玩一玩这个:101101,然后对x从-5到5都手算一遍看看规律。

    C

    很经典的贪心题。一个指针(p)在s上一直循环前往后扫,另一个指针在z上,一开始指向(z_1)。如果(p)指向的字母等于(z_1),那么就把z的指针往后移一格,相当于填入了一个字母。然后(p)继续扫,直到z的指针走到结尾。

    当然,这么写肯定会TLE,因此开26张表,每个表存放对应字母的出现位置,维护s的当前指针位置(p),接下来需要哪个字母了就去找这个字母的表里大于(p)的最小位置,如果不存在就把(p)放回起点,ans++。查找大于(p)的最小位置可以直接二分,直接调STL里的upper_bound就行。

    无解的情况不要忘了。

    D

    数学题,都是老套路了。

    给定(a,m),求有多少个(x)满足(0leq x < m)(gcd(a, m)=gcd(a+x,m))

    翻译一下,就是求

    (sumlimits_{x=0}^{m-1}[gcd(a,m)=gcd(a+x,m)])

    (g=gcd(a,m)),

    原式(=sumlimits_{x=0}^{m-1}[gcd(a+x,m)=g])

    (=sumlimits_{x=a}^{a+m-1}[gcd(x,m)=g])

    (=sumlimits_{x=1}^{a+m-1}[gcd(x,m)=g]-sumlimits_{x=1}^{a-1}[gcd(x,m)=g]).

    观察(sumlimits_{i=1}^x[gcd(i,m)=g])

    (=sumlimits_{i=1}^x[gcd(frac{i}{g},frac{m}{g})=1][g|i]) ((g|m))显然成立

    (=sumlimits_{i=1}^{lfloorfrac{x}{g} floor}[gcd(i,frac{m}{g})=1])

    (f(x,m)=sumlimits_{i=1}^x[gcd(i,m)=1]).

    容斥的想法很好理解:质因数分解m,二进制状压枚举它的每个质因子选或不选,加加减减就行。下面用反演也能推出一样的结果:

    (F(x,m,g)=sumlimits_{i=1}^x[g|gcd(i,m)])

    (=[g|m]sumlimits_{i=1}^x[g|i])

    (f(x,m,g)=sumlimits_{i=1}^x[g=gcd(i,m)])

    因此(f(x,m,g)=sumlimits_{g|d}^{dleq lfloorfrac{x}{g} floor}mu(frac{d}{g})F(x,m,d))

    因此(f(x,m)=f(x,m,1)=sumlimits_{d=1}^{lfloorfrac{x}{g} floor}mu(d)[d|m]sumlimits_{i=1}^x[d|i])

    (=sumlimits_{d|m}^{dleq lfloorfrac{x}{g} floor}mu(d)lfloorfrac{x}{d} floor)

    这个式子的含义就和上面说的容斥一样。

    (mleq 10^9),因此质因子最多七八个,肯定能过。

    (Ans=f(lfloorfrac{a+m-1}{g} floor, frac{m}{g})-f(lfloorfrac{a-1}{g} floor, frac{m}{g})).

    E

    非常巧妙的一道线段树题目。

    建立一个数组(B)和一个变量(val)(b_i)表示一开始在第(i)个数后面切这一刀,之后调整两边的元素使左边小于等于(val),右边大于(val)的最小代价。

    从小往大枚举(val),数组也会随之改变。如果(val)(v)变成(v+1),那么对(b_i)进行观察:

    (v+1)在第(k)位(即(p_k=v+1)),

    (k>i),那么原来(p_k)呆在右边,现在它要调换到左边,因此(b_i)要加上(a_k).

    (k leq i),那么原来(p_k)呆在左边,需要被调换到右边,但现在不需要调换了,因此(b_i)要减去(a_k).

    换句话说,就是这么两个操作:

    1.区间加减一个数;

    2.查询整个数组的最小值。

    直接上线段树就行。

    F

    非常牛逼的一道dp。

    一个数组,每一位都有一个随机的取值范围,问最后随机出一个不上升的数组的概率。(nleq 50, a_ileq 1e9).

    实际上就是统计不下降的数组的个数(把数组倒过来看就行。。。)

    这么考虑:最多2n个端点,把它们全都标到一根数轴上,把线段从左往右分成(O(n))段。一个小trick是把原来的每个右端点+1,也就是把区间从([l,r])变成([l,r+1))(S_1=<l_1,r_1>,S_2=<l_2,r_2>,...(l_1leq r_1leq l_2leq r_2...))

    (f(i,j))表示数组选择了数组的前(i)个元素,且都选择在前(j)条线段上的方案数。

    假如知道了(f(i,j)),那么我们可以枚举一个(k),表示在第(j+1)条线段上选择数组的接下来(k)个元素((k)可以为0)。由于线段互不相交且从左往右排序,无论在这条线段上怎么选择,最后都是一个不上升的数组。

    那么就可以从状态(f(i,j))转移到(f(i+k,j+1))

    最后一个问题是如何在线段(S_{j+1}=<l_{j+1},r_{j+1}>=[l_{j+1},r_{j+1}))上选择(k)个元素(可重复)?这个是非常经典的组合数学问题,求不定方程(x_1+x_2+...+x_n=k)的非负整数解的个数。运用挡板法(另一种叫法叫Stars and Bars,都一样),很容易知道这个结果是组合数(C_{k+n-1}^{n-1}=C_{k+n-1}^k).

    因此有转移方程(f(i+k,j+1)+=f(i,j)*C_{k+n-1}^{k}).计算一次转移是(O(k)=O(n))的,

    因为(C_{k+n-1}^k=frac{(k+n-1)!}{k!(n-1)!}=frac{1}{k!}prodlimits_{i=n}^{n+k-1}i).一个状态的前驱状态最多有(O(k)=O(n))个,而一共有(O(n*2n)=O(n^2))个状态,所以总复杂度是(O(n^4))的。事实上在转移时顺带着计算组合数就能变成(O(n^3))了(吧?)

    后记

    太棒了,学到许多

  • 相关阅读:
    '?'变化左右括号,使得字符串括号匹配
    二叉树中最大值节电和最小值节点之间的路径
    python 处理传输层的报文 TCP/UDP
    hook笔记分享
    scrapy-splash学习
    pycharm解决关闭flask后依旧可以访问服务
    python一些常用代码块
    阿里系纯滑块验证码破解思路
    python代理池搭建
    关于scrapy的验证码处理
  • 原文地址:https://www.cnblogs.com/zhugezy/p/12262379.html
Copyright © 2011-2022 走看看