zoukankan      html  css  js  c++  java
  • xjoi Day11 T2题解

    众所周知,我的博客园断更很长时间了。。。但是最近突然发现博客园可以用 markdown 然后就回来用一次。
    题目链接:点我
    30pts做法:
    直接暴力一下就好了,(n^2) 枚举 (i,j),然后 (O(1)) 计算贡献即可。

    50pts做法:
    使用 (cnt[x]) 数组表示 (1-m) 中所有数中,二进制下第 (x) 位有多少个是 (1),那么 (sum_{i=0}^{m} p or i) 就可以直接
    (p) 二进制拆分,然后如果第 (k) 位是 (0),那么这一位对答案的贡献就是这一位 (1) 的个数,而如果是 (1)的话
    就和 (cnt[k]) 无关了,而贡献直接就是 (m+1),所以 (sum_{i=0}^{m} p or i) 这个式子就很好算了。然后我们枚举
    每一个 (i,1leq ileq n),然后把每一个 (i) 当成 (p) ,然后就能 (O(nlog n)) 做了。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int NR=1e5+10;
    const int mod=1e9+7;
    int n,m;
    ll cnt[50];
    ll ans;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*f;
    }
    int main()
    {
        n=read(),m=read();
        for(int i=0;i<=m;i++)
        {
            int tot=0,t=i;
    	while(t)
    	{
    	    tot++;
    	    cnt[tot]+=(t&1);
    	    t>>=1;
    	}
        }
        for(int i=0;i<=n;i++)
        {
    	int t=i;
    	for(int x=1;x<=30;x++)
    	{
    	    ans+=(t&1)?((1ll*m+1<<x-1)%mod):((1ll*cnt[x]<<x-1)%mod);
    	    ans%=mod;
    	    t>>=1;
    	}
        }
        printf("%lld",ans%mod);
        return 0;
    }
    

    100pts做法:
    考虑在50pts上优化,我直接对于 (n,m) 都初始化出来一个 (cnt)(cnt[x]) 表示第 (x) 位上有几个 (0),分别记为
    (cnt1,cnt2),然后对于每一位处理,答案就是 (n imes m-cnt1[x]times cnt2[x]),但是由于 (n,m) 都是从 (0)
    开始,所以是要把 (n++,m++)。记住,一定要及时取模,我考试的时候就因为取模问题 (100pts->50pts)
    代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int NR=1e5+10;
    const int mod=1e9+7;
    ll n,m;
    ll cnt[NR],cnt2[NR];
    ll ans;
    ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*f;
    }
    int main()
    {
        n=read()+1,m=read()+1;
        for(int i=1;i<=60;i++) cnt[i]=m-(((m>>i)<<i-1)+max(0ll,(m%(1ll<<i)-(1ll<<i-1))));
        for(int i=1;i<=60;i++) cnt2[i]=n-(((n>>i)<<i-1)+max(0ll,(n%(1ll<<i)-(1ll<<i-1))));
        for(int i=1;i<=60;i++) ans+=((n%mod*(m%mod)%mod-cnt[i]%mod*(cnt2[i]%mod)%mod)*((1ll<<i-1)%mod))%mod,ans%=mod;
        printf("%lld",(ans%mod+mod)%mod);
        return 0;
    }
    
  • 相关阅读:
    转载--C 的回归
    学嵌入式不是你想的那么简单--转载
    scanf() 与 gets()--转载
    getchar、getch、getche 与 gets()
    scanf()函数原理
    C/C++头文件一览
    再论函数指针、函数指针数组
    初论函数指针、指针函数、指针的指针
    转载--一个“码农”自述的血泪史:当了35年程序员,我最大的遗憾就是没抓住机遇转行
    转载--协方差的意义和计算公式
  • 原文地址:https://www.cnblogs.com/chen-1/p/13860950.html
Copyright © 2011-2022 走看看