解题思路
拆位运算,简单的所就是一位一位计算贡献就可以了
代码
#include
#include
#include
typedef long long LL;
using namespace std;
const int SIZE = 30 + 2;
const int MAXN = 1e5 + 5;
const int mod = 1e9 + 7;
int A[MAXN];
int n, p[SIZE];
int main(){
while(~scanf("%d", &n)){
int Max = 0;
for(int i = 1;i <= n;i ++){
scanf("%d", &A[i]);
Max = max(Max, A[i]);
}
LL ans = 0;
for(int i = 0;i < SIZE;i ++){//and
LL sum = 0, last = 0;
memset(p, 0, sizeof(p));
for(int j = 1;j <= n;j ++){
if(A[j] >> i & 1LL){
for(int k = 0;k < SIZE;k ++){//or
if(A[j] >> k & 1LL){
p[k] = j;
}
sum = (sum + (1LL << k) * (p[k] - last)) % mod;
}
}
else{
for(int k = 0;k < SIZE;k ++){
p[k] = j;
}
last = j;
}
}
ans = (ans + sum * (1LL << i)) % mod;
}
printf("%I64d\n", ans);
}
return 0;
}
解题思路
对于是否存在 x 一个数,只需要 gcd(a1,a2,a3,...) ,其中 an ,表示为 x 的倍数,当所有 x 的倍数的最大公约数等于 x 的时候表示 x 这个数一定存在在这个集合中
代码
#include
#include
#include
#define FIN freopen("input.txt", "r", stdin)
using namespace std;
const int MAXN = 1e5 + 5;
const int MAXM = 1e6 + 5;
int n;
int A[MAXN];
bool vis[MAXM];
int gcd(int a, int b){
return b ? gcd(b, a % b) : a;
}
int main(){
//FIN;
while(~scanf("%d", &n)){
int Max = 0, ans = 0;
memset(vis, false, sizeof(vis));
for(int i = 0;i < n;i ++){
scanf("%d", &A[i]);
if(!vis[A[i]]) ans ++;
vis[A[i]] = true;
Max = max(Max, A[i]);
}
//printf("[%d]\n", Max);
for(int i = 1;i <= Max;i ++){
if(vis[i]) continue;
int w = -1;
for(int j = i;j <= Max;j += i){
if(!vis[j]) continue;
if (w == -1) w = j;
w = gcd(w, j);
}
if(w == i) {
ans ++;
}
}
printf("%d\n", ans);
}
return 0;
}
解题思想
直接看成异或,
代码
#include
#include
#include
using namespace std;
typedef long long ll;
const ll p = 1000000007;
int main() {
ll A, B, C;
scanf("%lld%lld%lld", &A, &B, &C);
ll t = 2, ans = 1;
while (C) {
if (C & 1) ans = (ans * t) % p;
t = (t * t) % p;
C >>= 1;
}
printf("%lld\n", ans);
return 0;
}
解题思路
这道题目思维一直纠结
官方题解
为了方便起见
我们令 n<m 且 n,m 互质(若n,m不互质可以分为多个若干子问题)
假设有nm局,那么每一对都打过,因此可以将这些先统计出来,k变成一个不大于nm的数
这里,如果n,m不互质,那么并不是每一对都会打,例如n=4,m=6则小A的第一个数和小B的第2个数是无论如何都不会打的。
令小A的4个数编号为1,2,3,4,小B的6个数编号为1,2,3,4,5,6。
那么可以分成的两个子问题为。
小A的1,3与小B的1,3,5以及小A的2,4与小B的2,4,6打。这样不断变为若干子问题,直到最后n,m互质。
接下来,我们考虑如果打了k局,那么对于前k%n个数都打了k/n+1局,后面的数都打了k/n局,我们可以先将前k%n个数的第k/n+1局单独拎出来,累加进答案里。问题转换成对于每个数,都要打k/n局。
我们考虑对于第一个数,每次与它打的位置依次是多少,即
1,n%m+1,2n%m+1,3n%m+1….
可以观察到,这个序列实际上是长度为m的循环序列。
因此对于1~n的每个数,只要在这个序列中找到最先出现的,接下来连续k/n个数即为与它打的位置,这里可以通过前缀和O(1)更新答案。
这样就可以在O(m)线性时间内找出答案。
代码
待补…太麻烦啦