蒟蒻表示只能在看了题解之后a掉第一题。。。
T1
题目大意:用一个数a[]的二进制表示一个集合(a[]=5=(101)2,表示集合{1,3}),求a[i]的子集中满足不是a[i-b[i]]~a[i-1]任何一个的子集的个数。
思路:搜索每一个子集,保存一下各种集合的最后一次出现的地方,如果在要求的范围之外就可以取,更新数组,否则就不能取,然后输出就可以了。因为位运算是个渣,所以就用的dfs(调小常数,有两点措施,一是把这个子集的十进制数当参数传入并变化;二是用数组保存2的几次方,比一遍遍的位运算要快。),效果也不错,没有超时。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int la[100001]={0},er[20]={0},a[100001]={0},b[100001]={0},ci=0,jie[20]={0}; void zer(int x) { int i=0; memset(er,0,sizeof(er)); while(x>0) { if (x%2==1) { ++er[0];er[er[0]]=i; } x>>=1; ++i; } } void work(int i,int x,int t) { int j; if (i>er[0]) { if (la[t]<x-b[x]&&t>0) ++ci; la[t]=x; return; } work(i+1,x,t); work(i+1,x,t+jie[er[i]+1]); } int main() { freopen("hope.in","r",stdin); freopen("hope.out","w",stdout); int n,i,j; jie[1]=1; for (i=2;i<=19;++i) jie[i]=jie[i-1]<<1; scanf("%d",&n); for (i=1;i<=n;++i) { scanf("%d%d",&a[i],&b[i]); zer(a[i]);ci=0; work(1,i,0); printf("%d\n",ci); } fclose(stdin); fclose(stdout); }
时间: 2024-10-12 11:45:57