zoukankan      html  css  js  c++  java
  • 51nod1674:区间的价值2(分治,利用&和|的收敛性)

    lyk拥有一个区间。

    它规定一个区间的价值为这个区间中所有数and起来的值与这个区间所有数or起来的值的乘积。
    例如3个数2,3,6。它们and起来的值为2,or起来的值为7,这个区间对答案的贡献为2*7=14。
    现在lyk有一个n个数的序列,它想知道所有n*(n+1)/2个区间的贡献的和对1000000007取模后的结果是多少。
     
    例如当这个序列为{3,4,5}时,那么区间1,11,1,1,21,2,1,31,3,2,22,2,2,32,3,3,33,3的贡献分别为9,0,0,16,20,25。

    Input第一行一个数n(1<=n<=100000)。 
    接下来一行n个数ai,表示这n个数(0<=ai<=10^9)。Output一行表示答案。Sample Input

    3
    3 4 5

    Sample Output

    70

    题意:求所有区间的&值乘|值。

    思路:分治,利用这两个逻辑运算的收敛性,用map记录相应个数,然后累加即可。

    (和前面利用gcd的收敛性分治的一样的。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=100010;
    const int Mod=1000000007;
    ll ans;
    ll a[maxn],And[maxn],Or[maxn]; 
    map<pair<ll,ll>,ll>mp;
    map<pair<ll,ll>,ll>::iterator it;
    void solve(int L,int R)
    {
        if(L>R) return ;
        int Mid=(L+R)>>1; mp.clear();
        And[Mid]=a[Mid]; Or[Mid]=a[Mid];
        mp[make_pair(And[Mid],Or[Mid])]++;
        for(int i=Mid-1;i>=L;i--){
            And[i]=And[i+1]&a[i];
            Or[i]=Or[i+1]|a[i];
            mp[make_pair(And[i],Or[i])]++;
        }
        for(int i=Mid;i<=R;i++){
            for(it=mp.begin();it!=mp.end();it++)
                ans+=(ll)(And[i]&(*it).first.first)*(Or[i]|(*it).first.second)%Mod*(*it).second%Mod;
        }
        solve(L,Mid-1); solve(Mid+1,R);
    }
    int main()
    {
        int N,i,j;
        scanf("%d",&N);
        for(i=1;i<=N;i++) scanf("%lld",&a[i]);
        solve(1,N);
        printf("%lld
    ",ans);
        return 0;
    }

     小小优化:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=100010;
    const int Mod=1e9+7;
    int a[maxn],And[maxn],Or[maxn]; ll ans;
    map<pair<int,int>,int>mp,tp;
    map<pair<int,int>,int>::iterator it1,it2;
    void solve(int L,int R)
    {
        if(L>R) return ;
        int Mid=(L+R)>>1; 
        mp.clear(); tp.clear();
        And[Mid]=a[Mid]; Or[Mid]=a[Mid];
        mp[make_pair(And[Mid],Or[Mid])]++;
        for(int i=Mid-1;i>=L;i--){
            And[i]=And[i+1]&a[i];
            Or[i]=Or[i+1]|a[i];
            mp[make_pair(And[i],Or[i])]++;
        }
        tp[make_pair(And[Mid],Or[Mid])]++;
        for(int i=Mid+1;i<=R;i++){
            And[i]=And[i-1]&a[i]; Or[i]=Or[i-1]|a[i];
            tp[make_pair(And[i],Or[i])]++;
        }
        for(it1=mp.begin();it1!=mp.end();it1++)
         for(it2=tp.begin();it2!=tp.end();it2++)
          ans=(ans+(ll)((*it1).first.first&(*it2).first.first)*((*it1).first.second|(*it2).first.second)%Mod*(*it1).second*(*it2).second)%Mod;
        solve(L,Mid-1); solve(Mid+1,R);
    }
    int main()
    {
        int N,i,j;
        scanf("%d",&N);
        for(i=1;i<=N;i++) scanf("%d",&a[i]);
        solve(1,N);
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    NYOJ 625 笨蛋的难题(二)
    NYOJ 102 次方求模
    ZJU Least Common Multiple
    ZJUOJ 1073 Round and Round We Go
    NYOJ 709 异形卵
    HDU 1279 验证角谷猜想
    BNUOJ 1015 信息战(一)——加密程序
    HDU 1202 The calculation of GPA
    "蓝桥杯“基础练习:字母图形
    "蓝桥杯“基础练习:数列特征
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9185351.html
Copyright © 2011-2022 走看看