zoukankan      html  css  js  c++  java
  • 【51nod1674】区间的价值 V2(算法效率--位运算合并优化+链表实现)

    题目链接:  51nod1674

    题意:定一个区间的价值为这个区间中所有数and起来的值与这个区间所有数or起来的值的乘积。现在l有一个 N 个数的序列,问所有n*(n+1)/2个区间的贡献的和对1000000007取模后的结果。

    解法:暴力是O(n^2),我是尽量找了相差1的区间之间的规律,枚举区间的右端点可以发现当区间 [ l , r ]在右边新添一个数 r+1 时,答案要加上 [r+1,r+1]、[r,r+1]、[r-1,r+1] ...... [1,r+1]。就可以每次存储 f [ i ] 和 g [ i ] 分别为 [ i , r ] 的“与”和“或”。再对 r+1 更新就好。
        当然暴力最先想到的其实是枚举左端点,右端点递增,若有 f[ ] * g[ ] 为0,就枚举下一个左端点,这样或许能水多一点分的。

        然而,正解确实是按我想的那个暴力的基础上优化为 O(n log n) 的。因为事实上每次存储的 f[ ] 和 g[ ],都有不少 f [ i ]=f [ j ] 且 g [ i ]=g [ j ],那么就可以合并,这样在枚举右端点的情况下扫描的数目就少了,数目为 log n 级别的。因为 n 的二进制有 log n 位,而每次变化最少是1个位变化,那么不同的 f[ ] 和 g[ ] 不同的组合数最多就是 2*log n(位变化成不同的数)了。那么我们也可以每次对 f[ ] 和 g[ ] 更新时考虑可并。若更新后的值有变化,要不是 f[ ] 有由 1→0,要不就是 g[ ] 有由 0→1,且是不可还原的,也就是不会再由 0→1 或 1→0。它就有可能变成和自己后面的一对 f[ ] 和 g[ ] 相同,若有相同的我们便把它们合并。使用链表实现。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<iostream>
     6 using namespace std;
     7 #define N 100010
     8 #define mod 1000000007
     9 typedef long long LL;
    10 
    11 LL a[N],sum;
    12 int st,ed;
    13 struct node{LL f,g;int t,next,last;}s[N];//f[i] 从i到当前的r-1的&值
    14 
    15 void ins(int x,int llast)
    16 {
    17     s[++ed].t=1; s[ed].f=s[ed].g=a[x]; 
    18     if (llast!=-1) s[ed].last=llast;
    19     else s[ed].last=ed-1;
    20     s[ed].next=ed+1;
    21     sum=(sum+(a[x]*a[x])%mod)%mod;
    22 }
    23 int main()
    24 {
    25     int n;
    26     scanf("%d",&n);
    27     for (int i=1;i<=n;i++)
    28       scanf("%I64d",&a[i]);
    29     st=1,ed=0; sum=0;
    30     ins(1,0);
    31     for (int r=2;r<=n;r++)
    32     {
    33       int llast=-1;
    34       for (int i=st;i<=ed;i=s[i].next)
    35       {//f 1→0 g 0→1
    36         s[i].f=(s[i].f&a[r])%mod;
    37         s[i].g=(s[i].g|a[r])%mod;
    38         sum=(sum+((LL)(s[i].f*s[i].g)%mod*s[i].t)%mod)%mod;
    39         int p=s[i].last;
    40         if (p && s[i].f==s[p].f && s[i].g==s[p].g)
    41         {
    42           if (st==p) st=i;
    43           s[i].last=s[p].last;
    44           s[s[p].last].next=i;
    45           s[i].t+=s[p].t;
    46         }
    47         if (!s[i].f)
    48         {
    49           if (!p) st=s[i].next;
    50           if (s[i].next>ed) llast=p;//
    51           s[s[i].next].last=p;
    52           s[p].next=s[i].next;
    53         }
    54       }
    55       ins(r,llast);
    56     }
    57     printf("%I64d
    ",sum);
    58     return 0;
    59 }
    WA

    P.S.唉,这题做了2个多小时,还是WA了~TwT

  • 相关阅读:
    Unity3D游戏-愤怒的小鸟游戏源码和教程(一)
    Unity插件-ShareSDK使用指南
    Unity 3D开发-C#脚本语言的一些基础用法
    Shader的函数公式以及使用的场景
    Shader的基本用法和语法结构
    iTween的用法总结
    Unity 3D游戏-消消乐(三消类)教程和源码
    Unity 3D游戏-NPC对话系统With XML
    XML教程、语法手册、数据读取方式大全
    ReSharper2017.3的列对齐、排版格式、列对齐错误的修复
  • 原文地址:https://www.cnblogs.com/konjak/p/6068475.html
Copyright © 2011-2022 走看看