连飞学长的爱 解题报告 Apare_xzc

连飞学长的爱 解题报告

2019/2/22

vj链接


A-A
CodeForces - 560A
题意
有一套纸币,有n个币种,问是否能构成任意面值?
input:
n
a1 a2 … an
数据范围:
n<=1000 ai<=1e6

思路:
只要判断币种面值有没有1即可


B-B
CodeForces - 560B
题意:
有两张矩形的画,和一个矩形的墙,问墙上是否能放下两张画?
input:
a1 b1(墙的长、宽)
a2 b2(第一张画的长、宽)
a3 b3(第二张华的长、宽)
数据范围:
ai,bi<=1000

思路:
四种拼接方式,一种满足即可

bool solve()
{
    int x = a2+a3;
    int y = max(b2,b3);
    if(x<=a1&&y<=b1||x<=b1&&y<=a1) return true;
    x = a2+b3;
    y = max(b2,a3);
    if(x<=a1&&y<=b1||x<=b1&&y<=a1) return true;
    x = b2+a3;
    y = max(a2,b3);
    if(x<=a1&&y<=b1||x<=b1&&y<=a1) return true;
    x = b2+b3;
    y = max(a2,a3);
    if(x<=a1&&y<=b1||x<=b1&&y<=a1) return true;
    return false;
}

C-C
CodeForces - 559B
题意:
两个字符串满足下列两个条件之一输出yes:
(1) A[1,2…lena] == B[1,2…lenb]
(2) 把A分成前后长度相等的两部分a1+a2 B分成b1+b2,满足
(a1=b1且a2=b2) 或 (a1=b2且a2=b1)
输入:
(字符串)A
(字符串)B
数据范围
length <= 200 000

思路:
递归判断即可
拿到两个字符串A,B

  • 先判断A,B是否相等 若相等,return true;
  • else if len为奇数,return false;
  • else return (a1=b1且a2=b2) 或 (a1=b2且a2=b1)
  • 这里可以剪枝:如果字符串A,B中相同字母出现的次数不同,直接return false;
    我的代码<-戳这里

D-D
CodeForces - 559C
题意: 小学奥数题升级版->走网格
网各为h*w (h,w<=1e5)
有n个格子是黑色的,其余是白色的(n<=2000)
从左上角走到右下角,每次只能向下或向右走1格(不能走到格子外面)
其中黑色的格子不能走,问从左上角到右下角的方案数,答案对1e9+7取模
数据范围
1<=h,w<=1e5
1<=n<=2000
mod = 1000 000 007
思路:

  • 这道题,小学奥数的做法是一行一行的递推
    因为只能向下走或向右走,所以从起始走到格子(i,j)的方案数dp[i][j] = dp[i-1][j] + dp[i][j-1] (dp[1][1]==1)
    遇到黑色的格子,直接dp[i][j] = 0;

  • 如果没有黑色的格子,从起始位置(1,1)走到格子(i,j)的方案数就是C(i+j-2,i)。因为从(1,1)到(i,j)总距离为垂直距离i-1加上水平距离j-1,令tot = i-1+j-1,只是在tot步中选择i-1步往下走
    C(n,m)代表组合数

  • 为了叙述方便我们先写一个函数Dis(x0,y0,x1,y1)
    其中x1>=x0, y1>=y0 这个函数表示从点(x0,y0)走到点(x1,y1)的方案数
    则Dis(x0,y0,x1,y1) = C(x1-x0+y0-y1,x1-x0)

  • 因为黑色格子的个数n比较少,我们可以从黑色格子入手
    如果一个格子(i,j)的左上方没有其它的黑色格子,则起始点到它的走法为Dis(1,1,i,j)
    如果一个格子(i,j)的左上方有黑色格子(a,b)那么不能由P走到当前的格子,所以要减去(a,b)到(i,j)的方案数
    假设起始格子到(a,b)的方案数dp(a,b)已知,则要减去的数为:dp(a,b) * Dis(a,b,i,j)

  • 所以,从起始格子走到右下角的方案数就是Dis(1,1,h,w)减去所有在它左上方的黑色格子(a,b)对它的影响:dp(a,b)*dis(a,b,h,w) 而计算起点到黑色格子(a,b)的方案数又要用(a,b)左上方的黑色格子的方案
    所以把所有的黑色格子按先x后y排序,一次求出dp(xi,yi)即可
    这里我们可以O(n)预处理出2e5以内的所有阶乘和阶乘的逆元

int N = 2e5;
int mod = 1e9+7;
long long Fac[N+10],rev[N+10];
void init()
{
    Fac[0] = 1;
    for(int i=2; i<=N; ++i)
        Fac[i] = Fac[i-1]*i%mod;
    //对质数取模,逆元Rev(x) = x^(mod-2)
    rev[N] = fast_pow(Fac[N],mod-2);
    for(int i=N-1; i>=1; --i)
        rev[i] = rev[i+1]*i%mod;//逆元的性质
}
long long C(long long n,long long m)
{
    if(!m||m==n) return 1ll;
    return Fac[n]*rev[m]%mod*rev[n-m]%mod;
}

我的代码


E-E
CodeForces - 558C
题意:
给n个正整数(n<=100000),a1,a2…an(1<=ai<=100000)
每操作一次,可以把任意一个数乘以2或者除以2(整数除法)
问最少操作多少次可以使这n个数都相同?

输入:
n
a1 a2… an
数据范围:
1<=n<=100 000
1<=ai<=100 000

思路:
用二进制模拟

  • 先把所有的数都写成二进制的形式按高位对齐,每一位求n个数的和,若cnt[i]==n说明n个数的这一位都是1,简记为c[i]
  • 一个数乘以2相当于在它后面加了一个0,除以2相当于删去了最后一位(0或1)
    高位 -> 低位
    3: 1 1
    5: 1 0 1
    6: 1 1 0
    c: 3 2 1
  • 我一开始的思路是这样的:
    从最高位开始,
    如果c[i]==0说明n个数该为全是0或者有的数没有这么多位,可以通过乘以2添加0;
    如果c[i]==n,说明这n个数该为均为1;如果0<cnt[i]<n 则有的为1,有的为0,因为无法凭空产生1,所以i前面的相等的数就是最后每个ai操作后的结果
    找到第一个0<cnt[i]<n的位数,己它前面有x位,所以结果为 sum(abs(bitof(a[i]-x)) i=1,2…n
  • 然后就Wa了
  • 其实还有一种情况,虽然我们不能凭空添加1,但是我们可以删去1和添加0
    看一个死亡样例:(下面6个数是二进制形式,高位对齐)
    101100 0000
    101100 0000
    101100 0000
    101100 0000
    101101
    1011
    显然,按照刚才的思路,只有前5位cnt[i]为0或n
    那么如过ai最后可以都变成10110或者1011或者101或者10或者1你应该懂我意思吧
    就是说所取前1,2,3,4,5位都可以
    取一个操作最少的就是答案
    ans = |10-5|*4 + |6-5|+|4-5| = 22
    但是其实,我们可以把第5第6个数都变为101100 0000
    第5个数除一次,乘5次,第6个数乘6次
    ans = 5+1+6 = 12显然比22小

这是因为: 刚才的思路碰到多余的1就直接投降了,其实我们可以吧多余的1删掉,甚至还可以删掉1以后在后面添很多0
最后a[i]变为的相等的数可能位数比x要多,设为y
当然,二进制形式的x位之后全部是0
我的代码


F-F
CodeForces - 558D
题意:
有一棵满二叉树,高度为h(1<=h<=50),顶点为序号1,顶点为第1层
叶子节点都在第h层,其中,有一个出口在某个叶子节点上
然后有q(q<=1e5)个询问,每个询问有4个数cent L R ans
问在第cent层序号范围在[L,R]的节点的是否有出口的祖先?(自己也是自己的祖先) ans=1表示有,ans=0表示没有

输入:
h q
cent1 L1 R1 ans1
cent2 L2 R2 ans2

centq Lq Rq ansq

输出
若给的数据自相矛盾输出“cheated…”
若能判断出出口所在叶子节点的序号,输出序号
否则输出“data is not suffient”
数据范围:
1<=h<=50
0<=q<=1e5

思路:
离线处理,给定一组L,R,可以求出其在第h层的所有子节点[l,r]
把ans=1的放一起,ans=0的放一起,按区间左端点排序

  • 若h=1则出口一定在1,稍加判断即可
  • 若只有ans = 1的询问,则若有两个区间完全不相交,说明两有多个出口,矛盾; 若最后求得所有区间交集为0,也矛盾;若交集长度>1则数据不充足;若区间长度为1,输出这个r
  • 若只有ans = 0的区间,则存在多个区间,是没有出口的,若若叶子节点的全集减去这些区间的交集所得的差集为0,说明没出口,矛盾; 若差集长度只有一个长度为1的区间,则是答案;若差集有多个区间,则条件不充足
  • 若ans=0和ans=1均存在 先求出全集和ans=0差集,然后求ans=1的集合时,若有两个不想交的ans=1的集合,判断是否被否定
    若存在两个不相交的集合多没有被ans=0的询问否定则矛盾:
    否则看剩下的区间若长度为1,输出答案;
    若没有区间,则也矛盾;若只剩一个长度大于1的区间,则条件不充足

我的代码
(代码看似长,其实后面的case 3都是复制的case 1和2)


G-G
CodeForces - 527C
题意:
有一块玻璃,h*w(1<=h,w<=2e5)划线n次,每次在玻璃上垂直或水平画一条线,问每次画完线之后最大的矩形面积
输入:
h w n
ch1 x1
ch2 x2

chq xq
若ch = V表示垂直划
若ch = H表示水平画线
数据范围:
2<=h,w<=2e5
1<=n<=2e5
思路:
矩形面积最大,一定是长和宽最大
用set存线,用map存线之间的间距(很多人用mulitset都差不多)
每次找到离新画的线最近的两条线,得到x1,x2
map[x2-x1]–; map[x2-x]++; map[x-x1]++;
更新map值即可,若键对应的值为0,删除该节点
map的最大值为 *( --mp.end() )
(据说这道题正解是并查集?)
我的代码


H-H
CodeForces - 527D
题意:
N-P完全问题时间复杂度很难达到多项式的时间复杂度,如在n个点求一个最大的完全图的节点数
本题对于节点之间边的定义有所不同。
有n个点(1<=n<=2e5),所有点都在X轴上,每个点有坐标xi和重量wi,若两个点距离>=重量之和,则两个点之间有无向边
求这样的完全图的最大节点数
输入:
n
x1 w1
x2 w2

xn wn
数据范围:
1<=n<=2e5
0<=xi<=1e9
1<=wi<=1e9

思路:
分析见代码的注释部分
分析过后可以转化为经典的贪心问题:
最多可以完整的观看几个电视节目?

我的代码


I-I
CodeForces - 526C
题意:
意思大致是有两种糖果,每种无限多,一个爱吃糖果的小怪物最多吃capacity克的糖果,每种糖果一棵的重量和带来的开心度分别为wi和ei
求最大的开心度
输入:
capacity
w1 e1
w2 e2
数据范围:
均为[1,1e9]

思路:
有人说用完全背包做
我是直接w1取x个0-1e7个,暴力更新答案,然后w2再搞一遍
[我的代码(https://paste.ubuntu.com/p/BSMv9JK8Df/)


J-J
CodeForces - 526D
题意:
大致是说给一个长度为n的字符串S,为每个前缀是否可以看成是K+1个A和K个B交错组成的如下形式的字符串
ABABA…A (K+1个A,K个B, 其中A或B可以是空串)

输入:
n K
S

输出
长度为n的字符串,若长度为i的前缀可以看成ABA…A(K个B)这种形式,就在第i位输出1,否则输出0

数据范围:
1<=n,k<=1000 000

思路:
由于所求的串是循环的,所以我们需要知道每个前缀的循环节
可以用kmp算法中的next数组求得
kmp求最小循环节
定理:若长度为len的字符串S存在最小循环节,则循环节的长度L = len - next[len]
循环节为S的子串[S0,S1,S2…S(L-1)]
看一个例子:
15 2
abcabcabcabctql
1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 (index)
a b c a b c a b c a b c t q l (S)
0 0 0 1 2 3 4 5 6 7 8 9 0 0 0 (Next)
1 1 1 1 1 2 2 2 3 3 3 4 1 1 1 (x)
循环节的长度为L,则循环次数x = len/L(向下取整)
现在有三种情况:

  • case 1:B串为空串,则需要出现K+1个完整的A
    所以这时,只要保证len%L=0且x%(k+1)=0即可
  • case 2:A串为空串,则需要出现K个完整的B
    与上一种情况同理,len%L==0 且 x%K=0
  • case 3: A串和B串都不为空
    若(最小的)循环节为D,则
    当len%L=0时:原串可以表示为DDD…D(x个D)
    当len%L!=0时,原串可以表示位DDD…Dd(其中有x个D,d为D长度为len%L的前缀)
    len%L!=0的情况比较一般,因为我们可以吧D也看作是d
    设D = d(前缀) + p(除去前缀的后缀)
    设AB = C
    则A可以写成DD…D(D的个数可能为0)的形式,B可以写成pDD…D(D的个数可能为0)的形式
    CCC…CA(K个C)
    C.length = len/L
    A.length = len%L
    由于C.length > A.length,则一个充分条件就是len/K > len%L
    只要满足了这个条件,那么就可以把长度为L的前缀看成C(A+B),把长度为len%L的前缀看成A
    我能不能说除了这种方法构造不出来ABABA的串,所以这也是必要条件

我的代码


K_K
CodeForces - 535C
题意:
题意有点儿不好读懂
给一个无限长的首项为A公差为B的等差数列
有多个询问,每次给L m t
表示最多可以操作t次,每次最多可以使m个数减一,
问从L开始,最多可以使多长的区间都减为零?
输入:
A B n
一下为n组询问:
l t m
数据范围:
A,B <= 1e6
n<=1e5

思路:
二分:由于最多操作t次,所以区间右边端点<=t
区间和小于等于t*m
这道题让我知道即使开了取消同步cin,cout还是妥妥的TLE

我的代码


L-L
CodeForces - 535D
题意:
给一个字符串P,要构造一个长度为n的字符串S,这个字符串要满足匹配子串P至少m次,给出m个匹配的位置posi,表示构造出的字符串P的第posi位到第posi+p.length-1位的子串必须和p完全一样,求能构造出多少种满足条件的字符串(答案对1e9+7取模)
输入:
n m
pos1 pos2 … posm

数据范围:
1 ≤ n ≤ 1000 000
0 ≤ m ≤ n-|p|+1

思路:
照题意模拟。pos从小到大排序,若两个pos之差>=lengthOf§则一定有解,若大于,则未涉及的位置可以任意取26个字母,cnt += posj-posi
两个串有重叠,则要满足题意,相交的部分要为模式串的前缀和后缀的公共部分
预处理出所有前缀和后缀相同的公共部分,用KMP的Next数组可以得到模式串前后缀最长的公共部分
存在多个相同的前后缀,则一定有循环:
p[1,2] == p[19,20] 且 p[1,2,3,4] == p[17,18,19,20]
=>p[1,2]==p[3,4]==p[19,20]==p[17,18]
可以预处理出字符串P所有可以和前缀匹配上的后缀的长度(有点儿抽象,看下面这个例子)
例如abcabcababcczzzzzabcabcabc
其中所有满足条件的后缀的长度就是3,6,9
然后按题意模拟,如果重叠了且重叠的后缀长度和前缀无法匹配,则直接输出0,return 0;
若不冲突,则输出26^cnt

我的代码


ps: 第一次markdown,还是挺好用的
从2月22号早上开始写,火车下铺写了一下午,写到电脑没电,然后今天晚上终于写完了。

完成时间:2019/2/23 21.07

地点: 1105

猜你喜欢

转载自blog.csdn.net/qq_40531479/article/details/88983472