(补题)
补一下ZOJ的两道签到题吧(还是有点思想,当时也没那么快看出来)
Little Sub and Pascal’s Triangle
题意:求杨辉三角第n行的奇数的个数。
思路:第n行杨辉三角就是组合数Cn k(1 <= n <= k),
题目所求奇数和可转换为:sigma(Cn k) (mod 2)(1<=k<=n)的和,
有组合取模自然可以想到lucas定理:
lucas(n,k,p) = c(n % p,k % p) * lucas(n / p, k / p, p) (p是质数,此题目p = 2)
等价转换到对应的p进制中,
所求的其实n转换成2进制,n的二进制上为1的位置对答案产生2 ^ pos的贡献。
AC code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int getone(ll n){
int res = 0;
while(n > 0){
if(n & 1) ++res;
n >>= 1;
}
return res;
}
int main(){
ll n;
int T;
cin >> T;
while(T--){
cin >> n;
unsigned long long ans = 1LL << (getone(n-1));
cout << ans << endl;
}
return 0;
}
Little Sub and Mr.Potato’s Math Problem
思路:找规律构造,可见博客:https://www.luogu.org/blog/user20547/solution-p2022
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[20];
ll f[20];
void init(){
f[0] = 0, f[1] = 1;
for(int i = 2; i < 19; ++i){
f[i] = f[i-1] * 10;
}
}
int getbase(int x,int &pos){
pos = 0;
while(x > 0){
a[pos++] = x % 10;
x /= 10;
}
for(int i = 0, j = pos - 1; i <= j; ++i,--j){
x = a[i], a[i] = a[j], a[j] = x;
}
int res = 0,num = 0;
for(int i = 0; i < pos; ++i){
num = num * 10 + a[i];
res += num - f[i + 1] + 1;
}
return res;
}
int main(){
init();
int T,k,m,len;
scanf("%d",&T);
while(T--){
scanf("%d%d",&k,&m);
bool ok = true;
for(int i = 1; i <= 10; ++i){
if(k == f[i] && m != i){
puts("0");
ok = false;
break ;
}
}
if(!ok) continue ;
int base = getbase(k,len);
if(base == m){
printf("%d\n",k);
continue ;
}
if(base > m){
puts("0");
continue ;
}
ll ans = f[len + 1];
m -= base;
for(int i = 1; ;++i){
ll tmp = k * f[i + 1] - f[len + i];
if(m > tmp){
m -= tmp;
ans *= 10;
}else break ;
}
ans += m - 1;
printf("%lld\n",ans);
}
return 0;
}