肥宅快乐数
肥宅快乐数
Time limit:1s Memory limit:128M
Description
作为一个肥宅,栗酱每天都从不同的事物上获得快乐。今天他发现每一个形如 (i,j) 的二元组当满足 “i + j == i | j” 时都会给他带来1点快乐。现在问题来了,[1, 2^k] 以内的正整数一共能带给栗酱多少点快乐呢?
答案对1e+7取模
Input
数据的第一行是数据组数T。
在每组数据中:第一行是一个整数k。
T <= 128
k <= 128
Output
每组数据一行,直接输出答案。
Sample Input
2
1
10
Sample Output
2
59048
HINT
(2,1)和(1,2)算不同的二元组
这是我参加的2018年绍兴市市赛的一道题,当时做此题时因组合数过大不会处理而未能做出此题,回来之后参考了一些资料成功解出来了,现补上代码,纪念我的第一道组合数取余。
#include"bits/stdc++.h" using namespace std; typedef long long LL; const int mod=1e9+7; int c[130][130]; int quick_pow(int n,int m){ int ans=1; while(m){ if(m&1) ans=1ll*ans*n%mod; n=1ll*n*n%mod; m>>=1; } return ans; } //这个comb用来求组合数取余,借鉴了https://blog.csdn.net/u012860428/article/details/41317231大佬的代码针对这题优化了一下 int comb(int n,int m){ int ans=1; for(int i=1;i<=m;i++){ int x=n-m+i; ans=ans*(1ll*x*quick_pow(i,mod-2)%mod)%mod; } return ans; } int main(){ for(int i=1;i<=128;i++){ c[i][0]=1; for(int j=1;j<=i;j++){ if(j>(i>>1))c[i][j]=c[i][i-j]; else c[i][j]=comb(i,j); } } for(int i=1;i<=100;i++) printf("%d ",c[100][i]); int T,n; scanf("%d",&T); while(T--){ scanf("%d",&n); //当i等于1<<n时,j只要小于1<<n都满足题目要求,同样当j等于1<<n时,i只要小于1<<n也满足要求,这里一个有(1<<n+1)-2个二元组 int ans=quick_pow(2,n+1)-2; //现在i或j等于1<<n的情况都考虑过了,再来考虑i和j都不等于1<<n的情况 //也就是在n个2进制位里随意取i个为1,组成的数为题目所说的i,在剩下的n-i个二进制位里随意取j个二进制位为1,组成的数为题目所说的j //但是为了满足i和j大于等于1的要求,所以i不能把n个二进制位都取完,所以循环里用i<n for(int i=1;i<n;i++) ans=(ans+(1ll*quick_pow(2,n-i)-1)*c[n][i])%mod; printf("%d\n",ans); } return 0; }
大佬的组合数取余代码如下(前提是p为素数)转自:https://blog.csdn.net/u012860428/article/details/41317231
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; typedef long long LL; LL n,m,p; LL quick_mod(LL a, LL b) { LL ans = 1; a %= p; while(b) { if(b & 1) { ans = ans * a % p; b--; } b >>= 1; a = a * a % p; } return ans; } LL C(LL n, LL m) { if(m > n) return 0; LL ans = 1; for(int i=1; i<=m; i++) { LL a = (n + i - m) % p; LL b = i % p; ans = ans * (a * quick_mod(b, p-2) % p) % p; } return ans; } LL Lucas(LL n, LL m) { if(m == 0) return 1; return C(n % p, m % p) * Lucas(n / p, m / p) % p; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%I64d%I64d%I64d", &n, &m, &p); printf("%I64d\n", Lucas(n,m)); } return 0; }