**:hnust_derker
模+位運算,現在還是不打能明白,先留個記錄。
/**
hdu 6085 rikka with candies
題意:a陣列n個數,b陣列m個數,q個查詢, 每次給出乙個k,詢問有多少對(i,j), 使得ai % bj = k, 輸出對數對模2的值
思路:首先,用乙個vis陣列01方式記錄a陣列中的數是否出現過,因為有ai % bj = k,所以也就是(ai - k) % bj = 0,不妨設ai - k = x,那麼bj則是x的因子,因為
是ai % bj = k,所以k一定比bj小,即k的取值範圍是[0, bj)那麼可以列舉每個x, 再列舉每個x的因子c,如果c不在b陣列出現, 就不管它;否則的話,就在[0, bj)
中的每乙個y的值, 對應的加上vis陣列中x + y的值,舉個例子:
vis陣列中對於6 7 8 9 10 11的出現情況是0 1 1 0 1 0
對於x列舉到6,它的因子列舉到3(假設3在b陣列存在)的時候,如果有(ai - k) % 3 = 0,那麼就是說,如果k可以取值,k在[0, 3)也就是[0, 2]的範圍內,也就轉換為
ai = x + k, 也就是6 + [0, 2],那麼現在只需要看對應取值為k的時候,x + k(ai)是否存在,如果存在那麼k的值即可加上1, 因為此時(ai, 3)形成了一對模為k的數
設res陣列是記錄餘數為k的對數, x=6,c=3的情況如下所示
vis 6 7 8 9 10 11
0 1 1 0 1 0
x+k 6 7 8
res[0, 1, 2] + vis[x + 0, x + 1, x + 2]
= res[0, 1, 2] + vis[6, 7, 8]
= res[0, 1, 2] + [0, 1, 1]
就是說res[0]+0, res[1]+1, res[2]+1, 代表有(6+1)%3=0,(6+2)%3=0,
即(7, 3)形成了一對餘數為1的數,(8, 3)形成了一對餘數為2的數
還有因為直接相加複雜度是o(n^2),題目說只需要模2, 那麼可以用異或來寫,用異或的話也不可能乙個乙個來,所以就用將連續若干個01值壓縮成乙個整數來異或,
這樣就是o(n^2 / 32), 還有一點就是對於x=0,因為所有正整數都是0的因子,對0分開寫,原式就是(0 + k) % bj = k => k % bj = k, 就是找在a陣列中k存在的前提
下,在b陣列中找出比k大的數的數量加進res[k]即可
**/#includetypedef long long ll;
const int maxn = 5e4 + 70;
using namespace std;
int a[maxn], b[maxn];
int res[maxn], vis[maxn];
vectorg[maxn];
ll dig[maxn][35];
setst;
ll ans[maxn];
void init()
sort(g[i].begin(), g[i].end());
}}int main()
for(int i = 0; i < m; i++)
sort(b, b + m);
for(int i = 1; i <= 5e4; i++)
}for(int i = 1; i <= max_data; i++) else }}
}int num = 0;
for(int i = 0; i * 32 <= 5e4; i++)
}for(int i = 0; i < n; i++)
while(q--)
}return 0;
}
巧妙的位運算及模運算
原帖 輸入2的n次方 如果突然要你輸入2的19次方,你是不是還要想一下呢?敲個524288多累啊。用位運算 1 19又快又準。乘除2的倍數 千萬不要用乘除法,非常拖效率。只要知道左移1位就是乘以2,右移1位就是除以2就行了。比如要算25 4,用25 2就好啦。判斷偶數 a 2取模是最常用的判斷方法之...
求模運算( )和按位與運算( )
最近看了看hashmap原始碼,覺得裡面的乙個按位與運算用的很優雅,記錄一下。jdk7中,hashmap是 陣列 鍊錶 的結構,為了讓hashmap裡的元素分布的更加均勻,就要在陣列中給每個元素乙個合適的位置,求模運算是乙個不錯的方法,但是,jdk7中使用了一種更加優雅的方法,原始碼中的方法如下 s...
取模運算 和按位與
最近在研究 redis 原始碼,發現一些平時不怎麼用的編碼習慣,感覺挺有趣,記錄下 function isodd1 num function isodd2 num 以上兩個方法都是用來判斷乙個數是否為奇數,但是用到的操作符不同,有什麼區別 取模操作符是基於 十進位制 人類思維 的一種取模方式,如 1...