题目链接: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 组合数+深搜(子集法)的更多相关文章

  1. HDU 5648 DZY Loves Math 暴力打表

    题意:BC 76 div1 1003有中文题面 然后官方题解看不懂,我就不说了,然后看别人的题解 因为询问i,j最大都是15000,所以可以预处理,res[i][j]代表答案,然后显然这是开不下的,也 ...

  2. BZOJ 3309: DZY Loves Math

    3309: DZY Loves Math Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 761  Solved: 401[Submit][Status ...

  3. 【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) ...

  4. DZY Loves Math系列

    link 好久没写数学题了,再这样下去吃枣药丸啊. 找一套应该还比较有意思的数学题来做. [bzoj3309]DZY Loves Math 简单推一下. \[\sum_{i=1}^n\sum_{j=1 ...

  5. bzoj 3462: DZY Loves Math II

    3462: DZY Loves Math II Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 211  Solved: 103[Submit][Sta ...

  6. [BZOJ3561] DZY Loves Math VI

    (14.10.28改) 本来只想写BZOJ3739:DZY Loves Math VIII的,不过因为和VI有关系,而且也没别人写过VI的题解,那么写下. 不过我还不会插公式…… http://www ...

  7. 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较小 ...

  8. ●BZOJ 3309 DZY Loves Math

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3309 题解: 莫比乌斯反演,线筛 化一化式子: f(x)表示x的质因子分解中的最大幂指数 $ ...

  9. DZY Loves Math 系列详细题解

    BZOJ 3309: DZY Loves Math I 题意 \(f(n)\) 为 \(n\) 幂指数的最大值. \[ \sum_{i = 1}^{a} \sum_{j = 1}^{b} f(\gcd ...

随机推荐

  1. 详解C中volatile关键字

    volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据.如果没有volatile关键字,则编译器可能优化读取和存储 ...

  2. div 显示滚动条的CSS代码

    div 显示滚动条的CSS代码   div显示上下左右滚动条 <div style="width:260px;height:120px; overflow:scroll; border ...

  3. 使用HttpClient发送请求、接收响应

    使用HttpClient发送请求.接收响应很简单,只要如下几步即可. 1.创建HttpClient对象.  CloseableHttpClient httpclient = HttpClients.c ...

  4. Java基础知识强化之网络编程笔记22:Android网络通信之 Android常用OAuth登录(获取个人信息)

    1. 获取百度个人信息(使用Gson解析): 2. 代码案例: (1)工程一览图,如下: (2)activity_main.xml: <LinearLayout xmlns:android=&q ...

  5. marine

  6. SQL学习笔记

    SQL(Structured Query Language)学习笔记 [TOC] Terminal登录数据库 1.登录mysql -u root -p ; 2.显示所有数据库show database ...

  7. aggregation 详解2(metrics aggregations)

    概述 权值聚合类型从需要聚合的文档中取一个值(value)来计算文档的相应权值(比如该值在这些文档中的max.sum等). 用于计算的值(value)可以是文档的字段(field),也可以是脚本(sc ...

  8. loadjs异步加载javascript回调

    function loadjs(url,callback){    var script=document.createElement('script');     script.type=" ...

  9. PV信号量的一些理解

    进程通常分为就绪.运行和阻塞三个工作状态.三种状态在某些条件下可以转换,三者之间的转换关系如下:   进程三个状态之间的转换就是靠PV操作来控制的.PV操作主要就是P操作.V操作和信号量.其中信号量起 ...

  10. dedecms自定义函数(二次开发)

    一些功能可能dedecms没有,这个时候可以自己写一些函数: 1.打开inlude->extend.func.php,将函数写到里面 比如:前台: [field:id function=&quo ...