2020上海ICPC区域赛——C题Sum of Log

2020上海ICPC区域赛——C题Sum of Log

题目链接:https://ac.nowcoder.com/acm/contest/9925/C

题意

给你 x x x y y y,让你求出
∑ i = 0 x ∑ j = [ i = = 0 ] y [ i \sum^{x}_{i=0}\sum^{y}_{j=[i==0]}[i i=0xj=[i==0]y[i& j = 0 ] [ l o g 2 ( i + j ) + 1 j=0][log_{2}(i+j)+1 j=0][log2(i+j)+1

题解

首先我们要把题目中的公式转换一下,
i i i& j = = 0 j==0 j==0
⌊ l o g 2 ( i + j ) + 1 ⌋ \lfloor log_{2}(i+j)+1 \rfloor log2(i+j)+1即表示 i i i j j j中最高的非 0 0 0二进制位。
eg: 20 20 20& 8 = = 0 8==0 8==0 20 20 20的二进制位为 10100 10100 10100 8 8 8的二进制位为 01000 01000 01000 ⌊ l o g 2 ( 20 + 8 ) + 1 ⌋ = 5 \lfloor log_{2}(20+8)+1 \rfloor=5 log2(20+8)+1=5,即为 20 20 20的最高非 0 0 0二进制位。
因此问题就变的简单了许多。
这次数位 d p dp dp的状态和牛客多校第六场的H题类似。
首先我们需要维护数位 d p dp dp中固定的一维,即枚举到了第几位。
后面两维也比较套路,即一维维护是否超过 x x x数位上限,一维维护是否超过 y y y数位上限。
还有一维维护是否前一位是否是前导 0 0 0
剩下的状态就需要我们仔细考虑了。
第一印象肯定是直接维护最高的非 0 0 0二进制位。
但是算一下数据范围发现会超时。
那么我们怎么优化就比较关键了。
因为我们要维护的是最高的非 0 0 0二进制位,
而我们之前已经维护了一维来纪录前导 0 0 0,每当当前位的前一位是前导 0 0 0且当前位为 1 1 1时,即表示当前位会对后面所有合法数的个数产生贡献,因此这个状态已经足够我们维护答案了。
状态:
d p [ p o s ] [ s x ] [ s y ] [ l e a d ] dp[pos][sx][sy][lead] dp[pos][sx][sy][lead]表示当前位为 p o s pos pos,sx表示是否已经超过 x x x数位上限,sy表示是否已经超过 y y y数位上限, l e a d lead lead表示前一位是否为前导 0 0 0
剩下的过程算是数位 d p dp dp的套路,枚举x的数位和 y y y的数位也算是牛客多校的套路。

代码

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define pY puts("YES")
#define pN puts("NO")
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
#define outval2(a,b) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b << "\n";
#define outval3(a,b,c) cout << "Debuging...|" << #a << ": " << a <<"\t"<< #b << ": " << b <<"\t"<< #c << ": " << c << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int mod = 1e9+7;
int a[40],b[40];
ll dp[40][2][2][2];
int len;
ll dfs(int pos,int sx,int sy,int lead){
    if(pos==-1) return 1;
    if(dp[pos][sx][sy][lead]!=-1) return dp[pos][sx][sy][lead];
    ll ans=0;
    int up1=(sx?a[pos]:1);
    int up2=(sy?b[pos]:1);
    rp(i,0,up1){
        rp(j,0,up2){
            if(i&j) continue;
            ll num=1;
            if(lead&&(i||j)) num=pos+1;
            ans=(ans+1ll*dfs(pos-1,sx&&i==up1,sy&&j==up2,lead&&!i&&!j)*num%mod)%mod;
        }
    }
    return dp[pos][sx][sy][lead]=ans;
}
void solve(){
    int x=read(),y=read();
    mst(dp,-1);
    len=0;
    while(x||y){
        a[len]=(x&1);
        b[len]=(y&1);
        y>>=1;
        x>>=1;
        len++; 
    }
    cout<<(dfs(len-1,1,1,1)-1+mod)%mod<<endl;
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    //time_t beg, end;
    //if(debug) beg = clock();

    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值