一般容斥,具体思想参考代码实现,刚开始是在读入时处理所有数的二进制子集,没看$N$的范围以为复杂度不会爆炸..
然后复杂度就爆炸了。
小优化:
每次整个载入二进制,计数。这个结束后枚举计数的状态和答案的状态。
up(i,1,(1<<10)-1)up(j,1,(1<<10)-1)if((j&i)==j)f[j]+=T[i]; up(i,1,(1<<10)-1)f[i]=(f[i]-1)*f[i]/2;
下面是代码的具体实现。
1 //OJ 1376 2 //by Cydiater 3 //2016.9.18 4 #include <iostream> 5 #include <cstdio> 6 #include <cstring> 7 #include <string> 8 #include <algorithm> 9 #include <queue> 10 #include <map> 11 #include <ctime> 12 #include <cmath> 13 #include <iomanip> 14 #include <cstdlib> 15 using namespace std; 16 #define ll long long 17 #define up(i,j,n) for(int i=j;i<=n;i++) 18 #define down(i,j,n) for(int i=j;i>=n;i--) 19 const int MAXN=1<<15; 20 const int oo=0x3f3f3f3f; 21 inline ll read(){ 22 char ch=getchar();ll x=0,f=1; 23 while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} 24 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 25 return x*f; 26 } 27 ll N,T[MAXN],num,ans=0,f[MAXN]; 28 namespace solution{ 29 void init(){ 30 N=read(); 31 memset(f,0,sizeof(f)); 32 up(i,1,N){ 33 ll S=0;num=read(); 34 while(num>0){ 35 int tmp=num%10; 36 S|=(1<<tmp); 37 num/=10; 38 } 39 T[S]++; 40 } 41 up(i,1,(1<<10)-1)up(j,1,(1<<10)-1)if((j&i)==j)f[j]+=T[i]; 42 up(i,1,(1<<10)-1)f[i]=(f[i]-1)*f[i]/2; 43 } 44 void slove(){ 45 up(s,1,(1<<10)-1){ 46 int cnt=0; 47 up(i,0,9)if(s&(1<<i))cnt++; 48 if(cnt%2)ans+=f[s]; 49 else ans-=f[s]; 50 } 51 } 52 void output(){ 53 cout<<ans<<endl; 54 } 55 } 56 int main(){ 57 //freopen("input.in","r",stdin); 58 using namespace solution; 59 init(); 60 slove(); 61 output(); 62 return 0; 63 }
时间: 2024-09-28 22:58:29