牛客编程巅峰赛S2第1场

比赛地址:
青铜&白银&黄金
钻石&王者


A: 最小差值

  暴力求解。

B:Tree IV

  这个题采用模拟的方式去计算会超时。这就利用了二叉树的统计性质,设根结点的深度是1,那么每行的第一个结点的编号值是 2 d e p − 1 2^{dep-1} 2dep1,最后一个结点的编号值是 2 d e p − 1 2^{dep}-1 2dep1。这样就可以算出答案。

C:牛牛组数

   n n n个数,每个数只能用一次,要求要分成 k k k个数,使得和最大。很明显,先把 n n n个数按从小到大的顺序排序,前 k − 1 k-1 k1个数分别占前面 n − 1 n-1 n1个数的一个,最后 n − k + 1 n-k+1 nk+1个数构成最后一个数。因为 n n n的范围很大,所以要用高精度(只有加法)。

D:牛牛算题

  除法分块问题


【除法分块】
  基本思路:维护两个变量 L , R L,R L,R,代表当前的除数区间是 [ L , R ] [L,R] [L,R],在这样的一个闭区间中,满足商是一个定值。
  初始情况: L = 1 L=1 L=1,我们在 L ≤ N L\le N LN时循环进行:设 t = ⌊ N L ⌋ t=\big \lfloor \frac{N}{L} \big \rfloor t=LN,则当前答案区间的右端点是 R = ⌊ N t ⌋ R=\big \lfloor \frac{N}{t} \big \rfloor R=tN,那么下一个答案区间的左端点就是 L = R + 1 L=R+1 L=R+1.

例题1:P2261 [CQOI2007]余数求和

  典型的余数求和问题。我们知道 a % b = a − b ∗ ⌊ a b ⌋ a\%b=a-b*\big\lfloor\frac{a}{b}\big\rfloor a%b=abba.因此对于原式有:
∑ i = 1 n k   m o d   i = ∑ i = 1 n k − i ∗ ⌊ k i ⌋ = n ∗ k − ∑ i = 1 n i ∗ ⌊ k i ⌋ \sum_{i=1}^n k \bmod i=\sum_{i=1}^nk-i*\big\lfloor\frac{k}{i}\big\rfloor=n*k-\sum_{i=1}^n i*\big \lfloor \frac{k}{i} \big \rfloor i=1nkmodi=i=1nkiik=nki=1niik

#include<bits/stdc++.h>
#define close ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
int main()
{
    
    
    close;ll n,k;cin>>n>>k;
    ll bound=min(n,k),ans=0;
    for(ll L=1,R;L<=bound;L=R+1)
    {
    
    
        ll t=k/L;R=min(k/t,n);
        ans+=(L+R)*(R-L+1)/2*t;
    }
    cout<<n*k-ans;
}

例题2:U87406 整除分块

  这个题其实比上面的题目还裸,因为没有涉及到任何变形,唯一要记住的就是 ∑ i = 1 n i 2 = n ∗ ( n + 1 ) ∗ ( 2 n + 1 ) 6 \sum_{i=1}^n i ^2=\frac{n*(n+1)*(2n+1)}{6} i=1ni2=6n(n+1)(2n+1).

#include<bits/stdc++.h>
#define close ios::sync_with_stdio(false)
using namespace std;
const int mod=1e9+7;
typedef long long ll;
ll inv(ll base,ll x)
{
    
    
    ll ans=1;
    while(x){
    
    if(x&1) ans=ans*base%mod;base=base*base%mod;x>>=1;}
    return ans;
}
int main()
{
    
    
    close;int T;cin>>T;
    ll rec6=inv(6,mod-2);
    while(T--)
    {
    
    
        int n;cin>>n;
        ll last=0,ans=0;
        for(ll L=1,R;L<=n;L=R+1)
        {
    
    
            ll t=n/L;R=n/t;
            ll cur=R*(R+1)%mod*(2*R+1)%mod*rec6%mod;
            ans=(ans+((cur-last)%mod+mod)%mod*t%mod)%mod;
            last=cur;
        }
        cout<<ans<<endl;
    }
}

例题3:CF 2017-2018 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) C题

  这道题定义了 F ( n ) = ∑ p ∣ n n F(n)=\sum_{p|n}n F(n)=pnn,想要求解的是 S = ∑ a ≤ x ≤ b F ( n ) S=\sum_{a\le x\le b}F(n) S=axbF(n).如果我们仅仅从每个数字的因子个数入手,就必须判断这个数有哪些因子,不可取。而我们转换一下,我们考虑每个数能作为多少个数的因子来进行统计(有点像位运算求和的意思),这样就转换成了除法分块问题。
  我们令 S ( n ) = ∑ i = 1 n F ( n ) S(n)=\sum_{i=1}^n F(n) S(n)=i=1nF(n),那么就有 S = S ( b ) − S ( a − 1 ) S=S(b)-S(a-1) S=S(b)S(a1).然后对于 S ( n ) S(n) S(n)来说, i i i会成为 ⌊ n i ⌋ \big \lfloor \frac{n}{i} \big \rfloor in个数的因子,因此可以得出: S ( n ) = ∑ i = 1 n i ∗ ⌊ n i ⌋ S(n)=\sum_{i=1}^n i*\big \lfloor \frac{n}{i} \big \rfloor S(n)=i=1niin(注意最极限的答案会爆long long)

#include<bits/stdc++.h>
#define close ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
ull solve(ull x)
{
    
    
    if(x==1) return 1;
    ull ans=0;
    for(ull L=1,R;L<=x;L=R+1)
    {
    
    
        ull t=x/L;R=x/t;
        ans+=(L+R)*(R-L+1)/2*t;
    }
    return ans;
}
int main()
{
    
    
    close;ull a,b;cin>>a>>b;
    ull ansa=solve(a-1),ansb=solve(b);
    cout<<ansb-ansa;
}

  回到原来的D题上,其实这道题经过化简,就是要求解: ∑ p = 1 n ( ⌊ n p ⌋ ) ∗ ( n − p ∗ ⌊ n p ⌋ ) = n ∗ ∑ p = 1 n ⌊ n p ⌋   − ∑ p = 1 n p ∗ ( ⌊ n p ⌋ ) 2 \sum_{p=1}^n \big ( \big \lfloor \frac {n}{p} \big \rfloor \big )* \big ( n-p* \big \lfloor \frac {n}{p} \big \rfloor \big )=n*\sum_{p=1}^n \big \lfloor \frac {n}{p} \big \rfloor \ - \sum_{p=1}^n p* (\big \lfloor \frac {n}{p} \big \rfloor)^2 p=1n(pn)(nppn)=np=1npn p=1np(pn)2回到了最初的分块问题上。

const int mod=1e9+7;
class Solution {
    
    
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 返回1-n的所有k*m的和
     * @param num long长整型 正整数 n
     * @return long长整型
     */
    long long inv(long long base,long long x)
    {
    
    
        long long ans=1;
        while(x){
    
    if(x&1) ans=ans*base%mod;base=base*base%mod;x>>=1;}
        return ans;
    }
    long long cowModCount(long long num) {
    
    
        long long rec2=inv(2,mod-2);
        long long ans=0;
        for(long long L=1,R;L<=num;L=R+1)
        {
    
    
            long long t=num/L;R=num/t;
            ans=(((ans+num*t%mod*(R-L+1)%mod)%mod-t*t%mod*(L+R)%mod*(R-L+1)%mod*rec2%mod)%mod+mod)%mod;
        }
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/CUMT_William_Liu/article/details/111242521
今日推荐