题目
Codeforces 261C Maxim and Matrix
给定一个谜一般的矩阵,求2 to n+1行中有多少行中1的个数等于t.
矩阵是这样的.以下是
时候的矩阵.
这是一个非常漂亮的分形矩阵.如果光光让你打表估计都得是个D题.
000000000000000000000000000000000000000000000000000000000000000000000000000000001
000000000000000000000000000000000000000000000000000000000000000000000000000000010
000000000000000000000000000000000000000000000000000000000000000000000000000000101
000000000000000000000000000000000000000000000000000000000000000000000000000001000
000000000000000000000000000000000000000000000000000000000000000000000000000010100
000000000000000000000000000000000000000000000000000000000000000000000000000100010
000000000000000000000000000000000000000000000000000000000000000000000000001010101
000000000000000000000000000000000000000000000000000000000000000000000000010000000
000000000000000000000000000000000000000000000000000000000000000000000000101000000
000000000000000000000000000000000000000000000000000000000000000000000001000100000
000000000000000000000000000000000000000000000000000000000000000000000010101010000
000000000000000000000000000000000000000000000000000000000000000000000100000001000
000000000000000000000000000000000000000000000000000000000000000000001010000010100
000000000000000000000000000000000000000000000000000000000000000000010001000100010
000000000000000000000000000000000000000000000000000000000000000000101010101010101
000000000000000000000000000000000000000000000000000000000000000001000000000000000
000000000000000000000000000000000000000000000000000000000000000010100000000000000
000000000000000000000000000000000000000000000000000000000000000100010000000000000
000000000000000000000000000000000000000000000000000000000000001010101000000000000
000000000000000000000000000000000000000000000000000000000000010000000100000000000
000000000000000000000000000000000000000000000000000000000000101000001010000000000
000000000000000000000000000000000000000000000000000000000001000100010001000000000
000000000000000000000000000000000000000000000000000000000010101010101010100000000
000000000000000000000000000000000000000000000000000000000100000000000000010000000
000000000000000000000000000000000000000000000000000000001010000000000000101000000
000000000000000000000000000000000000000000000000000000010001000000000001000100000
000000000000000000000000000000000000000000000000000000101010100000000010101010000
000000000000000000000000000000000000000000000000000001000000010000000100000001000
000000000000000000000000000000000000000000000000000010100000101000001010000010100
000000000000000000000000000000000000000000000000000100010001000100010001000100010
000000000000000000000000000000000000000000000000001010101010101010101010101010101
000000000000000000000000000000000000000000000000010000000000000000000000000000000
000000000000000000000000000000000000000000000000101000000000000000000000000000000
000000000000000000000000000000000000000000000001000100000000000000000000000000000
000000000000000000000000000000000000000000000010101010000000000000000000000000000
000000000000000000000000000000000000000000000100000001000000000000000000000000000
000000000000000000000000000000000000000000001010000010100000000000000000000000000
000000000000000000000000000000000000000000010001000100010000000000000000000000000
000000000000000000000000000000000000000000101010101010101000000000000000000000000
000000000000000000000000000000000000000001000000000000000100000000000000000000000
000000000000000000000000000000000000000010100000000000001010000000000000000000000
000000000000000000000000000000000000000100010000000000010001000000000000000000000
000000000000000000000000000000000000001010101000000000101010100000000000000000000
000000000000000000000000000000000000010000000100000001000000010000000000000000000
000000000000000000000000000000000000101000001010000010100000101000000000000000000
000000000000000000000000000000000001000100010001000100010001000100000000000000000
000000000000000000000000000000000010101010101010101010101010101010000000000000000
000000000000000000000000000000000100000000000000000000000000000001000000000000000
000000000000000000000000000000001010000000000000000000000000000010100000000000000
000000000000000000000000000000010001000000000000000000000000000100010000000000000
000000000000000000000000000000101010100000000000000000000000001010101000000000000
000000000000000000000000000001000000010000000000000000000000010000000100000000000
000000000000000000000000000010100000101000000000000000000000101000001010000000000
000000000000000000000000000100010001000100000000000000000001000100010001000000000
000000000000000000000000001010101010101010000000000000000010101010101010100000000
000000000000000000000000010000000000000001000000000000000100000000000000010000000
000000000000000000000000101000000000000010100000000000001010000000000000101000000
000000000000000000000001000100000000000100010000000000010001000000000001000100000
000000000000000000000010101010000000001010101000000000101010100000000010101010000
000000000000000000000100000001000000010000000100000001000000010000000100000001000
000000000000000000001010000010100000101000001010000010100000101000001010000010100
000000000000000000010001000100010001000100010001000100010001000100010001000100010
000000000000000000101010101010101010101010101010101010101010101010101010101010101
000000000000000001000000000000000000000000000000000000000000000000000000000000000
000000000000000010100000000000000000000000000000000000000000000000000000000000000
000000000000000100010000000000000000000000000000000000000000000000000000000000000
000000000000001010101000000000000000000000000000000000000000000000000000000000000
000000000000010000000100000000000000000000000000000000000000000000000000000000000
000000000000101000001010000000000000000000000000000000000000000000000000000000000
000000000001000100010001000000000000000000000000000000000000000000000000000000000
000000000010101010101010100000000000000000000000000000000000000000000000000000000
000000000100000000000000010000000000000000000000000000000000000000000000000000000
000000001010000000000000101000000000000000000000000000000000000000000000000000000
000000010001000000000001000100000000000000000000000000000000000000000000000000000
000000101010100000000010101010000000000000000000000000000000000000000000000000000
000001000000010000000100000001000000000000000000000000000000000000000000000000000
000010100000101000001010000010100000000000000000000000000000000000000000000000000
000100010001000100010001000100010000000000000000000000000000000000000000000000000
001010101010101010101010101010101000000000000000000000000000000000000000000000000
010000000000000000000000000000000100000000000000000000000000000000000000000000000
101000000000000000000000000000001010000000000000000000000000000000000000000000000
解法
首先还是打表并计算每一行1的个数.
1
1 2
1 2 2 4
1 2 2 4 2 4 4 8
1 2 2 4 2 4 4 8 2 4 4 8 4 8 8 16
1 2 2 4 2 4 4 8 2 4 4 8 4 8 8 16 2 4 4 8 4 8 8 16 4 8 8 16 8 16 16 32
1 2 2 4 2 4 4 8 2 4 4 8 4 8 8 16 2 4 ...
然后它们依然是按照
的幂次顺序自相似下去.
这个复制规律很像我前几天刚做过的一道洛谷题.
洛谷 p4317 花神的数论题
根据里面的原理都可以知道对于每一个
的幂次的部分,所有数出现的次数都是按照杨辉三角排列的.
那么我们用一个漂亮的
数位dp处理
以内
的每一个次幂出现的次数.
然后注意:此题又巨坑!
大家可以看到题目描述中要求的是
中出现的次数,所以:
第一个:n要+1!
第二个:第一个1不能要!
所以输入
之后将
,询问1的时候将
.否则会WA9.
为了卡到
最短代码,我把快读快写去掉,轻松成为最短代码.
#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
typedef long long ll;
ll n,t,dp[65];
int main(){
cin>>n>>t;++n;
if (t&t-1) return puts("0"),0;//明显t必须是2的次幂,不是直接输出0
int i,j,c=0;
for (j=60;~j;--j){
for (i=60;i;--i) dp[i]+=dp[i-1];
if (n>>j&1) ++dp[c++];
}++dp[c];//记住这4行dp!
for (c=0;t;t>>=1) ++c;//算t是2的多少次方
cout<<dp[c]-(c==1);//把c=1的情况减掉.
}
简短的代码背后,隐藏的是无尽的深思熟虑和巧妙的计算.
感谢那道花神的数论题.如果不是它,我就不能纯手切出这样的一道
题了.
下面是神仙styx的组合数倍增讨论解法,大家欣赏一下.
#include<map>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mod 1000000007
using namespace std;
long long dp[55][55],ans,n,t;
long long get(long long x)
{
long long tmp=1,cnt=0;
while(tmp!=x)
{
if(tmp>x) return -1;
tmp*=2;
cnt++;
}
return cnt;
}
int main()
{
for(int i=0;i<=50;i++)
{
dp[i][0]=dp[i][i]=1;
}
for(int i=1;i<=50;i++)
{
for(int j=1;j<=50;j++)
{
dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
}
}
scanf("%lld%lld",&n,&t);
t=get(t);
if(t<0)
{
puts("0");
return 0;
}
long long now=1,tmp=2;
while(tmp<=n)
{
n-=tmp;
ans+=dp[now][t];
tmp*=2;
now++;
}
now=0;
for(int i=50;i>=0;i--)
{
if(n&(1ll<<i))
{
if(t-now>=0) ans+=dp[i][t-now];
now++;
}
}
printf("%lld\n",ans);
}