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,1\leq i\leq n\),然后把每一个 \(i\) 当成 \(p\) ,然后就能 \(O(n\log 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\times 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;
}
posted @ 2020-10-22 20:53  CZD648  阅读(220)  评论(0编辑  收藏  举报
Live2D