2017.07.14【NOIP提高组】模拟赛B组

来源:互联网 发布:手机群发短信软件免费 编辑:程序博客网 时间:2024/06/05 10:45

T1:我们首先要知道一个性质,那就是若gcd(n/k,x)=1,那么gcd(n,k*x)=k。

所以我们每次枚举i,计算sum(gcd(i,j))(1<=j<i)时,如果存在一个j,有i%j=0且gcd(i,i/j)=1,那么这个j对答案的贡献就是j*phi(i/j)。

但是枚举j会超时,所以我们要优化。

我们可以在筛素数时求出phi,因为在筛素数时,素数i一定是i*j的一个质因子,结合phi计算公式,我们就可以更新phi[i*j]。然后我们再用线筛的思想去求出c[i](c[i]=sum(gcd(i,j))(1<=j<i)),最后对c[i]求出前缀和。


总结:sum(gcd(i,j)(1<=j<i))=sum(j*(phi(i/j))(i%j==0)),记住这条公式,因为这条公式很难用语言描述清楚。


T2:设f[i][j][k][r]表示第i行横着放的状态为j,第i行竖着放的状态为k,第i-1行竖着放的状态为r,那么我们枚举一个l表示i-1行横着放的状态为l,s表示第i-2行竖着放的状态为s。

要保证当前状态合法,我们得保证以下几件事情:

1、为了保证没有重叠,(j&k)=(j&r)=(k&r)=(l&r)=(s&l)=(s&r)=0

2、为了保证没有放在蜡烛上,(j&d[i])=(k&d[i])=(r&d[i])=(l&d[i-1])=(r&d[i-1])=(s&d[i-1])=(s&d[i-2])=0

3、我们得保证第i行不能横着放,第i行目前的状态为j|k|r|d[i](d[i]表示第i行蜡烛的状态),也就是j|k|r|d[i]的二进制表示中不能有两个连续的0,这个可以暴力判断。

4、我们得保证第i行和第i-1行结合起来的状态不能竖着放,他们结合起来的状态为j|k|d[i]|l|r|d[i-1],也就是j|k|d[i]|l|r|d[i-1]的二进制表示中没有0,这可可以表示成j|k|d[i]|l|r|d[i-1]=(1<<m)-1.

5、我们得保证第i-1行不能横着放,第i-1行目前的状态为l|r|d[i-1]|s,也就是l|r|d[i-1]|s的二进制表示中不能有两个连续的0,这个可以暴力判断。

满足以上条件之后,我们就可以进行状态转移,方程是f[i][j][k][r]=min(f[i][j][k][r],f[i-1][l][r][s]+j、k中1*2的矩阵的个数)。

赋初始值时,我们枚举一个j、k,j表示第1行横着放的状态,k表示第i行竖着放的状态,那么把j、k按以上条件判断一下,如果合法就f[1][j][k][0]=min(f[1][j][k][0],j、k中1*2矩阵的个数)。

最终答案就是f[n]中合法的最小值。


总结:多举反例有助于把情况考虑完全。


T3:这题zys神犇一次AC,我很好奇他是怎样想出那个解法的~~~

设g[x]表示第x号节点修改后的值一定得是g[x]的倍数,则g[x]=LCM(g[y1],g[y1]...g[yz])*cnt[x],y表示x的儿子,cnt[x]表示x的儿子的个数。若x为叶节点,那么g[x]=1。

接着我们来求一个节点x的ans,设min表示x的儿子y中a[y]的最小值,sum表示a[y]的和,那么所有a[y]要修改到的值m=min-(min%(g[x]/cnt[x]))。因为m*cnt[x]要是g[x]的倍数,所以m是g[x]/cnt[x]的倍数,又因为要使m尽量大,而m又不能超过min,所以m的计算公式如上。算出m之后,我们把所有a[y]更新为m,然后统计答案,第x个节点的答案=sum-cnt[x]*m。

原创粉丝点击