zoukankan      html  css  js  c++  java
  • loj2494 [hnoi2018]寻宝游戏

    题意:给你n个元素的数组a。你可以在每个元素之前添加and和or的符号。每次询问最后变成r有多少种添号情况。

    n<=1000,m<=5000,q<=1000.

    标程:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 using namespace std;
     5 const int mod=1e9+7;
     6 const int N=5005;
     7 typedef long long ll;
     8 int n,m,q,bin[N],tmp[N],rnk[N],bit[2],a[N],sum[N];
     9 int read()
    10 {
    11    int x=0;char ch=getchar();
    12    while (ch<'0'||ch>'9') ch=getchar();
    13    while (ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';break;}
    14    return x;
    15 }
    16 int main()
    17 {
    18     scanf("%d%d%d",&n,&m,&q);
    19     bin[0]=1;
    20     for (int i=1;i<=m;i++) rnk[i]=i;
    21     for (int i=1;i<=n;i++) bin[i]=(ll)bin[i-1]*2%mod;
    22     for (int i=1;i<=n;i++)
    23     {
    24         bit[0]=bit[1]=0;
    25        for (int j=1;j<=m;j++) bit[a[j]=read()]++,sum[j]=((ll)sum[j]+(ll)bin[i-1]*a[j]%mod)%mod;
    26        bit[1]+=bit[0];
    27        for (int j=m;j>=1;j--) tmp[bit[a[rnk[j]]]--]=rnk[j];
    28        swap(tmp,rnk);
    29    }
    30     reverse(rnk+1,rnk+m+1);
    31     while (q--)
    32     {
    33         for (int i=1;i<=m;i++) a[i]=read();
    34         int mx=0,mn=m+1;
    35         for (int i=1;i<=m;i++) 
    36           if (a[rnk[i]]==0) mn=min(mn,i);else mx=max(mx,i);
    37         if (mx>mn) {puts("0");continue;}
    38         int sum1=(rnk[mx]==0)?bin[n]:sum[rnk[mx]],//注意运算符二进制的长度为n 
    39         sum2=(rnk[mn]==0)?0:sum[rnk[mn]];
    40         printf("%d
    ",((ll)sum1-sum2+mod)%mod);
    41     }
    42    return 0;
    43 }

    易错点:1.注意运算符二进制的长度为n。bin要处理到2^n。

    题解:计数排序+性质/从后往前推+bitset

    bitset的做法:我们从后往前考虑,由最后一个数An和Ans可以推得前n-1个数的运算和x。

    枚举该位之前填&还是|,每一位有八种情况:

    x&1=1  x=1

    x&1=0  x=0

    x&0=1  无解,直接跳出

    x&0=0  ?任意

    x|1=1  ?任意

    x|0=1  x=1

    x|1=0  无解,直接跳出

    x|0=0  x=0

    无解不考虑,返回0。

    我们发现非任意的和Ans的答案是一样的,所以不用保存,只用bitset维护一样哪几个是?即可(这个可以自定义运算求)。如果都是?,那么接下来就没有限制了,返回2的若干次。

    但是枚举&和|,复杂度真的是对的吗?如果某一位相异,那么运算符唯一确定。反之是所有位相同的情况,得到的一定是111???,000???的这种形式。

    接下来如果同样所有位相同,以111???为例,推出来x要么全是?,直接返回,要么仍是全1,相当于也变成了唯一确定的状态。

    所以不能唯一确定的只有一次。好像会卡一点,手写bitset较宜。

    时间复杂度O(nmq/w)。

    出题人给的解法:

    设x为符号的二进制表示第i个数之前的符号如果是and,x[i]=1,反之x[i]=0。

    对于给出数列的每一位统计bi,第n个数的第i位是作为bi的最高位。

    容易发现,当x<bi时,最后答案的第i位应该是1,反之为0。

    那么对于每一个询问数,就可以列出关于x的不等式了。最后算出解区间中有多少个数即可。

    时间复杂度O(mq)。

  • 相关阅读:
    js里面的 InttoStr 和 StrtoInt
    预编译知识 (转载记录)
    C语言操作内存
    C语言操作文件
    C语言
    如何调试shell脚本
    设计模式-装饰者模式
    自己动手制作一个模版解析
    设计模式-单例模式
    http中关于缓存的那些header信息
  • 原文地址:https://www.cnblogs.com/Scx117/p/8861350.html
Copyright © 2011-2022 走看看