CoFun 1612 单词分组(容斥)

Description

Stan有N个不同的单词,这天,Stan新结交的两个朋友来他这里玩,Stan作为主人,他需要送给他们单词,但由于Stan不能偏心,所以Stan给每个单词一个权值v_i,他需要他这N个单词恰好分配给这两个朋友,这个地方的人很奇怪,他们用来定义自己的喜悦值的方式是把所有得到的单词的权值都位运算and起来的值,所以你需要使得两个朋友的喜悦值是相同的

好学的Stan不满足于求出一种方案,而是想要知道总共有多少种方案数,Stan觉得这个太简单了,所以请你来帮他解决吧。

Input Format

第一行包含一个整数N

第二行包含N个非负整数,表示每个单词的权值

Output Format

输出仅一行,即方案数

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #define ll long long
 7 ll f[2][1025][1025][2][2],ans=0;
 8 int n,a[1025],mx,bin[30];
 9 int b[55][105],m,num,fa[105];
10 int read(){
11     char ch=getchar();int t=0,f=1;
12     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
13     while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
14     return t*f;
15 }
16 void sbpianfen(){
17     for (int i=1;i<=n;i++){
18         int now=i&1,pre=now^1;
19         if (i==1){
20             f[now][a[i]][0][1][0]=1;
21             f[now][0][a[i]][0][1]=1;
22             continue;
23         }
24         for (int j=0;j<=mx;j++) for (int k=0;k<=mx;k++) for (int l=0;l<=1;l++) for (int z=0;z<=1;z++) f[now][j][k][l][z]=0;
25         for (int j=0;j<=mx;j++)
26          for (int k=0;k<=mx;k++){
27             if (k==0)
28              f[now][j&a[i]][k][1][0]+=f[pre][j][k][1][0];
29             f[now][j&a[i]][k][1][1]+=f[pre][j][k][1][1];
30             if (j==0)
31              f[now][j][k&a[i]][0][1]+=f[pre][j][k][0][1];
32             f[now][j][k&a[i]][1][1]+=f[pre][j][k][1][1];
33          }
34         for (int j=0;j<=mx;j++){
35          f[now][a[i]][j][1][1]+=f[pre][0][j][0][1];
36          f[now][j][a[i]][1][1]+=f[pre][j][0][1][0];
37         }
38     }
39     ans=0;
40     for (int i=0;i<=mx;i++)
41      ans+=f[n&1][i][i][1][1];
42     printf("%lld\n",ans);
43 }
44 int find(int x){
45     if (fa[x]==x) return x;
46     else return (fa[x]=find(fa[x]));
47 }
48 void dfs(int dep,int delta){
49     if (dep==m){
50         ans+=(ll)delta*(((ll)1<<num));
51         return;
52     }
53     dfs(dep+1,delta);
54     int tnum=num;
55     int tmp[51];
56     for (int j=0;j<n;j++) tmp[j]=fa[j];
57     int T;
58     for (T=0;!b[dep][T];T++);
59     int f=find(T);
60     for (int j=T+1;j<n;j++)
61       if (b[dep][j]){
62             int xx=find(j);
63             if (xx!=f){
64                 fa[xx]=f;
65                 num--;
66             }
67       }
68     dfs(dep+1,-delta);
69     for (int j=0;j<n;j++)
70      fa[j]=tmp[j];
71     num=tnum;
72 }
73 void sxpianfen(){
74     m=0;
75     for (int i=0;i<20;i++){
76         int t=1<<i,cnt=0;
77         for (int j=0;j<n;j++)
78          if (a[j]&t) cnt++;
79         if (cnt==0||cnt==n) continue;
80         for (int j=0;j<n;j++)
81          if (!(a[j]&t)) b[m][j]=1;
82          else b[m][j]=0;
83         m++;
84     }
85     for (int i=0;i<n;i++)
86      b[m][i]=1,fa[i]=i;
87     m++;
88     ans=0;
89     num=n;
90     dfs(0,1);
91     printf("%lld\n",ans);
92 }
93 int main(){
94     n=read();
95     for (int i=0;i<n;i++) a[i]=read();
96     sxpianfen();
97 }
时间: 2024-10-24 20:43:52

CoFun 1612 单词分组(容斥)的相关文章

POJ 2773 Happy 2006 二分+容斥(入门

题目链接:点击打开链接 题意: 输入n ,k 求与n互质的第k个数(这个数可能>n) 思路: solve(mid)表示[1,mid]中有多少个和n互质,然后二分一下最小的mid 使得互质个数==k solve(x) 实现: 与n互质的个数=所有数-与n不互质的数=所有数-(与n有一个因子-与n有2个因子的+与n有3个因子的) 状压n的因子个数,然后根据上面的公式容斥得到. #include <stdio.h> #include <iostream> #include <

hdu1695(莫比乌斯)或欧拉函数+容斥

题意:求1-b和1-d之内各选一个数组成数对,问最大公约数为k的数对有多少个,数对是有序的.(b,d,k<=100000) 解法1: 这个可以简化成1-b/k 和1-d/k 的互质有序数对的个数.假设b=b/k,d=d/k,b<=d.欧拉函数可以算出1-b与1-b之内的互质对数,然后在b+1到d的数i,求每个i在1-b之间有多少互质的数.解法是容斥,getans函数参数的意义:1-tool中含有rem位置之后的i的质因子的数的个数. 在 for(int j=rem;j<=factor[i

HDU 4135 Co-prime(容斥+数论)

Co-prime Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5526    Accepted Submission(s): 2209 Problem Description Given a number N, you are asked to count the number of integers between A and B

hdu 5664 Lady CA and the graph(树的点分治+容斥)

题意: 给你一个有n个点的树,给定根,叫你找第k大的特殊链 .特殊的链的定义:u,v之间的路径,经过题给的根节点. 题解:(来自BC官方题解) 对于求第k大的问题,我们可以通过在外层套一个二分,将其转化为求不小于mid的有多少个的问题. 接下来我们讨论如何求树上有多少条折链的长度不小于k. 我们考虑常规的点分治(对于重心,求出其到其他点的距离,排序+单调队列),时间复杂度为O(nlog^2n),但是这只能求出普通链的数量. 我们考虑将不属于折链的链容斥掉.也即,我们需要求出有多少条长度不小于mi

数学(容斥计数):LNOI 2016 方

Description 上帝说,不要圆,要方,于是便有了这道题.由于我们应该方,而且最好能够尽量方,所以上帝派我们来找正方形 上帝把我们派到了一个有N行M列的方格图上,图上一共有(N+1)×(M+1)个格点,我们需要做的就是找出这些格点形 成了多少个正方形(换句话说,正方形的四个顶点都是格点).但是这个问题对于我们来说太难了,因为点数太多 了,所以上帝删掉了这(N+1)×(M+1)中的K个点.既然点变少了,问题也就变简单了,那么这个时候这些格点组成 了多少个正方形呢? Input 第一行三个整数

[coci2011]友好数对 容斥

无趣的小x在玩一个很无趣的数字游戏.他要在n个数字中找他喜欢友好数对.他对友好数对的定义是:如果有两个数中包含某一个以上相同的数位(单个数字),这两个数就是友好数对.比如:123和345 就是友好数对,因为都包含数位3,显然123和234也是由号数对.而12和34则不是友好数对,因为它们没有相同的数位. 刚拿到题没怎么读懂,因为我直观的想法是存一下扫一遍就行了,后来一想,得用容斥:又犯蠢了: 其实这道题的容斥比较基本,看代码吧: #include<iostream> #include<c

HDU 5297 Y sequence 容斥/迭代

Y sequence Problem Description Yellowstar likes integers so much that he listed all positive integers in ascending order,but he hates those numbers which can be written as a^b (a, b are positive integers,2<=b<=r),so he removed them all.Yellowstar ca

Codeforces 611C New Year and Domino DP+容斥

"#"代表不能放骨牌的地方,"."是可以放 500*500的矩阵,q次询问 开两个dp数组,a,b,a统计横着放的方案数,b表示竖着放,然后询问时O(1)的,容斥一下, 复杂度O(n^2+q) #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cstdlib> #include<cmat

数论 + 容斥 - HDU 4059 The Boss on Mars

The Boss on Mars Problem's Link Mean: 给定一个整数n,求1~n中所有与n互质的数的四次方的和.(1<=n<=1e8) analyse: 看似简单,倘若自己手动推公式的话,还是需要一定的数学基础. 总的思路:先求出sum1=(1^4)+(2^4)+...(n^4),再求出sum2=(1~n中与n不互质的数的四次方的和),answer=sum1-sum2. 如何求sum1呢? 有两种方法: 1.数列差分.由于A={Sn}={a1^4+a2^4+...an^4}