hdu 5648 DZY Loves Math 组合数+深搜(子集法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5648
题意:给定n,m(1<= n,m <= 15,000),求Σgcd(i|j,i&j);(1 <= i <= n,1<=j<=m);
至多三组数据,至多两组数据max(n,m) > 2000.至多一组数据max(n,m) > 8000;
很多题解是用递推打表,将数据压缩250倍,即[i][j]:代表[1...250*i][1...250*j],之后零头就直接暴力求解;这样时间复杂度为O(T*250*max(n,m));
但是这并不完美。。代码长度接近5W b..如果卡代码长度的话,就呵呵了;
事先说明代码是在BC看的AC代码,来源于NanoApe。特在此orz..
思路:题解讲用枚举子集法,但是当时并没有看懂。。没有去细想在这个gcd里面是要确定什么,枚举什么。这就是深搜的思路了;
原本看到gcd想的就是莫队反演。。莫队反演是容易求出同一个gcd里面的对数;但是这道题gcd里面并不是原始的a,b;而是a,b的位或和位与运算以后的值;
并且数据规模不大,(至少从组数及n,m最大值的限制上来看);
现在我们就来枚举i|j,因为i&j能够在i|j枚举1,这就是题解上面的子集枚举的对象;
下面分情况来看如何深搜;i表示两个数位或运算后的值;并且默认n >= m
<1>当i<= m时,这时易知对于我们实际的值x,y一定是<=m的;直接在范围内枚举,即可dfs1();
dfs1里面a 代表位或的值,b代表位与的值;容易看出b其实位元1是在a中选的;至于对ans的贡献是每一个a位元为1,b为0的位可以是两种,所以1<<(c[a]-c[b]);对于b为0的情况,会出现x = 0 || y = 0所以减去这二者;(d在dfs2中解释);
注意并不是i <= n作为循环结束的标志,位或最大为2*n-1,这也是开始运算出mx的另一个用处;
<2>当i > m时,没有a里面的每一个1,一定有一个数(x||y)的位元是1的,这就可以分成x,y,x&&y;对应三个if;
对于这个位或值,如果前面有一个位1,原本x可以承担(即x += 1<<p 仍然<=n)但是并有没有取,而是被y承担了,这时之后任意位元为1的x均可以承担,这时对于x来说,进入dfs1就可以随便取a里面剩下的位了;这样就保证了所取得的值<=n;这就是为什么在判断是否能进入dfs1对后面的位元1进行组合数取的条件;即加的是(1<<(p+1))-1;
<3>对于dfs2中的p == -1的情况,是否需要求解?答案是要的,因为能到p == -1表示里面的x,y是符合情况的;如果不符合情况,就会直接在前面就无法dfs2下去了;直接计算即可;至于d的含义,因为当a > m时,前面大的位元1一定是x承担的,并且这承担的在后面组合数枚举的时候,虽然没有在高位上枚举,但是c[a]还是记录了这高位的,d即表示这没有枚举的高位a比b多出来的个数;由于枚举到的位可能在m范围内,但是之后却没有枚举,所以出现b = x&y;
很神奇~~~hhhhh
1326ms 1824k 自己手写__builtin_popcount()用时1263ms 因为库函数是查表的,并没有真正计算;
#include<bits/stdc++.h>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
#define MSi(a) memset(a,0x3f,sizeof(a))
#define inf 0x3f3f3f3f
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1|1
typedef pair<int,int> PII;
#define A first
#define B second
#define MK make_pair
typedef __int64 ll;
template<typename T>
void read1(T &m)
{
T x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
m = x*f;
}
template<typename T>
void read2(T &a,T &b){read1(a);read1(b);}
template<typename T>
void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
template<typename T>
void out(T a)
{
if(a>) out(a/);
putchar(a%+'');
}
int T,kase = ,i,j,k,n,m,x,y,a,b,d;
#define N 1<<16
int c[N];
ll ans;
inline ll gcd(ll a,ll b){return b == ?a:gcd(b,a%b);}
void dfs1(int p)
{
while(p >= ) {
if(!(a&(<<p))){p--;continue;}
b += (<<p);
dfs1(p-);
b -= (<<p);
p--;
}
if(b) ans += 1LL*gcd(a,b)*(<<(c[a]-c[b]-d));
else ans += 1LL*gcd(a,b)*((<<(c[a]-c[b]-d))-(x==?:)-(y==?:));//x,y分别是各自的实际值;
}
void dfs2(int p)
{
if(p == -){
if(x == || y == ) return ;
ans += gcd(x|y,x&y);
return ;
}
while(p >= && !(a&(<<p))) p--;
// **+(1<<p+1)-1是为了说明之后任意的枚举a中的位元1度不会超出n,m的范围
if(x+(<<p+)- <= n && y+(<<p+)- <= m){
b = x&y;
dfs1(p);
return ;
}
d++;//d表示x中1的个数比y中1的个数多d个
if(x+(<<p) <= n) x += <<p,dfs2(p-), x -= <<p;// x承担
if(y+(<<p) <= m) y += <<p,dfs2(p-), y -= <<p;// y承担
d--;
if(x+(<<p) <= n && y+(<<p) <= m)// x,y均承担
x += <<p, y += <<p, dfs2(p-), x -= <<p,y -= <<p;
}
int pop(unsigned x) //使用的是分治的思想
{
x = x - ((x>>) & 0x55555555);
x = (x & 0x33333333) + ((x >> ) & 0x33333333);
x = (x + (x >> )) & 0x0F0F0F0F;
x = x + (x >> );
x = x + (x >> );
return x & 0x0000003F;
}
int main()
{
rep0(i,,N) c[i] = pop(i);//__builtin_popcount
read1(T);
while(T--){
ans = ;
read2(n,m);
if(n < m) swap(n,m);
int mx = ;
while((<<mx) <= n) mx++;
rep1(i,,(<<mx)-){
if(i <= m) a = i,b = ,x = ,dfs1(mx);
else a = i,b = ,x = ,y = ,d = ,dfs2(mx);
}
out(ans);
puts("");
}
return ;
}
hdu 5648 DZY Loves Math 组合数+深搜(子集法)的更多相关文章
- HDU 5648 DZY Loves Math 暴力打表
题意:BC 76 div1 1003有中文题面 然后官方题解看不懂,我就不说了,然后看别人的题解 因为询问i,j最大都是15000,所以可以预处理,res[i][j]代表答案,然后显然这是开不下的,也 ...
- BZOJ 3309: DZY Loves Math
3309: DZY Loves Math Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 761 Solved: 401[Submit][Status ...
- 【BZOJ】3309: DZY Loves Math 莫比乌斯反演优化
3309: DZY Loves Math Description 对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007) ...
- DZY Loves Math系列
link 好久没写数学题了,再这样下去吃枣药丸啊. 找一套应该还比较有意思的数学题来做. [bzoj3309]DZY Loves Math 简单推一下. \[\sum_{i=1}^n\sum_{j=1 ...
- bzoj 3462: DZY Loves Math II
3462: DZY Loves Math II Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 211 Solved: 103[Submit][Sta ...
- [BZOJ3561] DZY Loves Math VI
(14.10.28改) 本来只想写BZOJ3739:DZY Loves Math VIII的,不过因为和VI有关系,而且也没别人写过VI的题解,那么写下. 不过我还不会插公式…… http://www ...
- BZOJ 3512: DZY Loves Math IV [杜教筛]
3512: DZY Loves Math IV 题意:求\(\sum_{i=1}^n \sum_{j=1}^m \varphi(ij)\),\(n \le 10^5, m \le 10^9\) n较小 ...
- ●BZOJ 3309 DZY Loves Math
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3309 题解: 莫比乌斯反演,线筛 化一化式子: f(x)表示x的质因子分解中的最大幂指数 $ ...
- DZY Loves Math 系列详细题解
BZOJ 3309: DZY Loves Math I 题意 \(f(n)\) 为 \(n\) 幂指数的最大值. \[ \sum_{i = 1}^{a} \sum_{j = 1}^{b} f(\gcd ...
随机推荐
- C#_Queue实例
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Queu ...
- Encryption
Encryption Configuration Basic Usage Encrypting a value Decrypting a value Configuration Before usin ...
- oracle数据库管理员简介、导入数据与导出数据
数据库管理员: sys和system的权限区别:sys:所有oracle的数据字典的基表和视图都存放在sys用户中,这些基表和视图对于oracle的运行时至关重要的,由数据库 自己维护,任何用户都不能 ...
- 多线程NSOperation
NSOperation(经常使用): 1.为什么会有NSOperation?弥补gcd的一些问题:1)下载为例子:如果gcd放到队列中的block操作面对网络有问题,block之外无法取消bloc ...
- [Oracle EBS R12]SQL Queries and Multi-Org Architecture in Release 12 (Doc ID 462383.1)
In this Document Abstract History Details Previous Releases Release 12 Multi-Org Session ...
- 让ubuntu开启ssh服务以及让vi/vim正常使用方向键与退格键
VIM 修复方法: 安装vim full版本,在full版本下键盘正常,安装好后同样使用vi命令.ubuntu预装的是vim tiny版本,而需要的是vim full版本.执行下面的语句安装vim f ...
- my_vimrc
" ----------------- Author: Ruchee" ----------------- Email: my@ruchee.com" --------- ...
- [转载][jQuery] Cannot read property ‘msie’ of undefined错误的解决方法
参考 [jQuery] Cannot read property ‘msie’ of undefined错误的解决方法 ---------------------------------------- ...
- Ceph Newstore存储引擎介绍
在Ceph被越来越多地应用于各项存储业务过程中,其性能及调优策略也成为用户密切关注讨论的话题,影响性能表现关键因素之一即OSD存储引擎实现:Ceph基础组件RADOS是强一致.对象存储系统,其OSD底 ...
- ASP连接11种数据库的常用语法
1.Access数据库的DSN-less连接方法: 以下为引用的内容: set adocon=Server.Createobject("adodb.connection") ado ...