[机房测试]10.28
10.26日原题大战,不是有手就能AK吗?,跳过
欢迎转载ssw02的博客:https://www.cnblogs.com/ssw02/p/11755483.html
地精部落
连接传送门:
T2
模拟一下即可。在画画图找找性质之后发现,由于可以无线次数交换,其实我们要求的可以分为3种情况,记录每种字符出现的次数外加统计特判即可。
分为 两偶数 一奇一偶 两奇数 即可 , 具体看代码
#include<bits/stdc++.h> using namespace std ; inline int read(){ int s=0 ; char g=getchar() ; while(g>'9'||g<'0')g=getchar() ; while( g>='0'&&g<='9' )s=s*10+g-'0',g=getchar() ; return s; } inline int getc(){ char g=getchar() ; while( g>'z'||g<'a')g=getchar() ; return (int)g-'a'+1 ; } int cnt[30] , N , M , T ; void clear(){ memset( cnt , 0 , sizeof(cnt) ) ; } void work1(){ int opt = false ; for( register int i = 1 ; i <= 26 ; ++i ) if( cnt[i]%4 ){ opt = true ; break ; } if( opt )puts("No") ; else puts("Yes") ; } void work2(){ int opt = 0 , tot = ( N/2*2 )*( M/2*2 ) ; for( register int i = 1 ; i <= 26 ; ++i ) if( cnt[i]%4 == 0 ){ if( cnt[i] > tot )cnt[i] -= tot , tot = 0 ; else tot -= cnt[i] , cnt[i] = 0 ; } else if( cnt[i] > 4 ){ int rd = cnt[i]/4*4 ; if( rd > tot )cnt[i] -= tot , tot = 0 ; else tot -= rd , cnt[i] -= rd ; } if( tot ){puts("No");return ;} for( register int i = 1 ; i <= 26 ; ++i ) if( cnt[i]%2 )opt++ ; if( opt ){puts("No");return;} puts("Yes") ; } void work3(){ int opt = 0 , tot = ( N/2*2 )*( M/2*2 ) ; for( register int i = 1 ; i <= 26 ; ++i ) if( cnt[i]%4 == 0 ){ if( cnt[i] > tot )cnt[i] -= tot , tot = 0 ; else tot -= cnt[i] , cnt[i] = 0 ; } else if( cnt[i] > 4 ){ int rd = cnt[i]/4*4 ; if( rd > tot )cnt[i] -= tot , tot = 0 ; else tot -= rd , cnt[i] -= rd ; } if( tot ){puts("No");return ;} for( register int i = 1 ; i <= 26 ; ++i ) if( cnt[i]%2 )opt++ ; if( opt != 1 ){puts("No");return;} puts("Yes") ; } int main(){ freopen("quilt.in","r",stdin) ; freopen("quilt.out","w",stdout) ; T = read() ; while( T-- ){ N = read() , M = read() ; int m1 ; for( register int i = 1 ; i <= N ; ++i ) for( register int j = 1 ; j <= M ; ++j ) m1 = getc() , cnt[m1]++; int tag = 0 ; tag = (N%2)+(M%2) ; if( tag == 0 )work1() ; else if( tag == 1 )work2() ; else work3() ; clear() ; } return 0 ; }
T3
T3相对复杂:直接搬运题解
原创题.
首先每只蚊子的贡献是独立的.如果一只蚊子经过了k个会被灭蚊器影响的点那么这个蚊子对答案的贡献是1-(1-p/q)k.
用1遍bfs求出哪些点是被灭蚊器影响的点.然后进行不同的处理.
n为树的点数,m为叶子节点数.
算法1:
对于每一只蚊子,做一遍bfs,O(m2)次bfs,复杂度O(nm2),期望得分10分
算法2:
通过一次bfs我们可以统计出一个叶子节点出发的所有蚂蚁的贡献.那么只需要m次bfs就可以了.复杂度O(nm).期望得分30分.
算法3:
对于d=0的测试点3,只有1号点被控制.那么经过了1号点的蚊子会贡献P/Q,我们只需要数一数有多少蚊子经过了1号点.这是非常好数的.期望得分10分.
算法4:
对于p/q=1的测试点4,蚊子只要经过被控制的点就必死无疑.我们只需要统计有多少只蚊子至少经过了一个被控制的点.我们以1为根建树,f[i]表示i所在子树内叶节点的个数,对于每一个被控制的点,我们统计以其为lca的路径条数.复杂度O(n). 这部分分对标算是有提示的.
算法5:
考虑对每一条路径进行讨论,求解lca之后算出这条路径经过的被影响的点数.复杂度应当为O(m2logn),但是细节较多,出题人没有写.
可以通过第6,7个测试点,结合前面的算法可以得到70分.
算法6(满分做法):
考虑对算法4进行拓展.此时每只蚊子的贡献是1-(1-p/q)k.我们可以先不管前面那个1,把后面的(1-p/q)k的和求出来,最后用m(m-1)减去那个和就可以了.
一条路径可以在LCA处拆成两条.我们考虑如何求出以某个点为LCA的所有路径的贡献之和.一条路径可以拆成两部分,一部分是从一个叶节点走到LCA,另一部分是从LCA走到另一个叶节点.把这两部分看作两条”半路径”.
记g[i]为以i为LCA的所有半路径的贡献之和.(即:对于i子树内的每个叶节点x,g[i]+=(1-p/q)k,k是x到i的半路径上的被控制点的个数).g[i]可以通过O(n)树形DP得到.
接下来我们通过g[i]求出以每个点为LCA的路径的贡献之和.
对于点x,考虑它的所有儿子,每一对儿子(u,v)的贡献是g[u]g[v]*(1-p/q)
注意,(u,v)和(v,u)都需要算一次.
直接暴力枚举每一对儿子会超时.我们通过乘法分配律可以O(儿子个数)的时间复杂度算出来.总的时间复杂度仍为O(n).空间复杂度也为O(n).但是常数可能较大,因此出题人给了5s的时限.
算法6:
本题属于树上路径统计问题,可以树分治.复杂度O(nlogn).期望得分50分.
可能有选手通过大力卡常数能够直接用树分治AC此题.