bitset题


牛客 Music Problem

题意:

给一个长度为n的数组a,问是否存在一个子序列,满足该子序列的和模3600等于0
数据范围:n<=1e5,a(i)<=1e9

解法:

比较裸的题,但是O(3600n)的算法不够优,
利用用bitset的整体移位,可以非常快的更新每轮答案。

code:

#include<bits/stdc++.h>
using namespace std;
signed main(){
    int T;cin>>T;
    while(T--){
        bitset<3600>t;
        int n;cin>>n;
        for(int i=1;i<=n;i++){
            int x;cin>>x;
            x%=3600;
            t|=(t<<x)|(t>>(3600-x));
            t[x]=1;
        }
        if(t[0])puts("YES");
        else puts("NO");
    }
    return 0;
}

hdu5890 Eighty seven

题意:

给定n个数,q组询问,每组询问给出x,y,z,表示删掉编号为x,y,z的数
问能否从剩下的数中选出10个数,满足这十个数的和为87
注意x,y,z中可能有部分数相等

数据范围:n<=50,q<=1e5

解法:

观察到q非常大,对于每组询问都计算一遍显然是不行的。
考虑到n很小,可以直接预处理所有情况,对于每组询问O(1)输出

预处理的过程用bitset优化

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=55;
int f[maxm][maxm][maxm];
bitset<88>d[11];//d[i]表示选择i个数可以达到的状态
int a[maxm];
int n;
bool check(int x,int y,int z){
    for(int i=1;i<=10;i++)d[i].reset();//清空
    d[0][0]=1;
    for(int i=1;i<=n;i++){
        if(i==x||i==y||i==z||a[i]>87)continue;
        for(int j=10;j>=1;j--){
            d[j]|=(d[j-1]<<a[i]);
        }
    }
    return d[10][87];
}
signed main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        memset(f,0,sizeof f);
        for(int i=1;i<=n;i++){
            for(int j=i;j<=n;j++){
                for(int k=j;k<=n;k++){
                    if(check(i,j,k)){
                        f[i][j][k]=f[i][k][j]=1;
                        f[j][i][k]=f[j][k][i]=1;
                        f[k][i][j]=f[k][j][i]=1;
                    }
                }
            }
        }
        int q;scanf("%d",&q);
        while(q--){
            int x,y,z;scanf("%d%d%d",&x,&y,&z);
            if(f[x][y][z])puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

牛客 简单瞎搞题

题意:

在这里插入图片描述
数据范围:n,l,r<=100

解法:

x(i)的可能取值为l2,(l+1)2…r2
注意到数据范围只有100,那么总和最大1e6,
开一个1e6的bitset,对于每一个x枚举其可能的取值,统计哪些值可以达到即可

code:

#include<bits/stdc++.h>
using namespace std;
bitset<1000000+5>t[105];
signed main(){
    int n;scanf("%d",&n);
    t[0][0]=1;
    for(int i=1;i<=n;i++){
        int l,r;scanf("%d%d",&l,&r);
        for(int j=l;j<=r;j++){
            t[i]|=(t[i-1]<<(j*j));
        }
    }
    printf("%d\n",t[n].count());
    return 0;
}

poj2443 Set Operation

题意:

有n个集合,每个集合S(i)有C(i)个数
q组询问,每组询问给出两个数x,y
问是否存在一个k,满足x在集合S(k)种,y也在集合S(k)中

数据范围:n<=1e3,C(i)<=1e4,1<=每个数<=1e4,q<=2e5

解法:

因为数的范围为1e4,集合数为1e3,
可以开1e4个bitset,每个bitset的大小为1e3,设第i个bitset为t(i)
如果集合k中出现了x,那么标记t(x,k)为1

判断x,y是否同时存在于一个集合,只需要判断t(x)&t(y)是否有含1的位即可

code:

#include<cstdio>
#include<bitset>
using namespace std;
bitset<1005>t[10000+5];//t[i][j]表示值i在第j个集合是否出现过
signed main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int k;scanf("%d",&k);
        while(k--){
            int x;scanf("%d",&x);
            t[x][i]=1;
        }
    }
    int q;scanf("%d",&q);
    while(q--){
        int x,y;scanf("%d%d",&x,&y);
        if((t[x]&t[y]).any())puts("Yes");
        else puts("No");
    }
    return 0;
}

发布了457 篇原创文章 · 获赞 37 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/105529959