Codeforces 261C/262E Maxim and Matrix 数位dp,组合数,数论,倍增

题目

Codeforces 261C Maxim and Matrix
给定一个谜一般的矩阵,求2 to n+1行中有多少行中1的个数等于t.
矩阵是这样的.以下是 n = 80 时候的矩阵.

这是一个非常漂亮的分形矩阵.如果光光让你打表估计都得是个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 ...

然后它们依然是按照 2 的幂次顺序自相似下去.
这个复制规律很像我前几天刚做过的一道洛谷题.
洛谷 p4317 花神的数论题
根据里面的原理都可以知道对于每一个 2 的幂次的部分,所有数出现的次数都是按照杨辉三角排列的.
那么我们用一个漂亮的 l o g 2 ( n ) 数位dp处理 n + 1 以内 2 的每一个次幂出现的次数.
然后注意:此题又巨坑!
大家可以看到题目描述中要求的是 2 n + 1 中出现的次数,所以:
第一个:n要+1!
第二个:第一个1不能要!

所以输入 n 之后将 n + 1 ,询问1的时候将 a n s 1 .否则会WA9.
为了卡到 c f 最短代码,我把快读快写去掉,轻松成为最短代码.

#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的情况减掉.
}

简短的代码背后,隐藏的是无尽的深思熟虑和巧妙的计算.
感谢那道花神的数论题.如果不是它,我就不能纯手切出这样的一道 E 题了.
下面是神仙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);
}

猜你喜欢

转载自blog.csdn.net/qq_31908675/article/details/81261920
今日推荐