题目链接:http://lightoj.com/volume_showproblem.php?problem=1172

题意:一个n进制(2<=n<=6)的数字,满足以下条件:(1)至少包含两位且不以0开头,比如012是不行的;(2)相邻数字不同;(3)定义这个数字x的score(x)等于相邻数字差的平方和,比如score(125)=(1-2)*(1-2)+(2-5)*(2-5)=10。现在给出n和m,求满足条件的所有n进制的数字中有多少数字的score为m。(1<=m<=10^9)

思路:首先我们使用简单的DP,设f[i][j]表示和为i以j结尾的数字个数。由于这个m很大,这样肯定是不行的。我们发现,这个DP转移的时候每次都是一样的,这正是可以运用矩阵的地方。我们将条件(1)中不能以0开头改为不能以0结尾,这其实是等价的。以下以n=3为例。我们用(i,j)表示和为i以j结尾的方案数,使用矩阵递推时,设矩阵为a,用s[m]表示score为m的方案数,我们用[s[1],s[2],s[3],s[4]]*a=[s[2],s[3],s[4],s[5]],因为要加上以j结尾的状态,我们用s[i,j]表示以j结尾score为i为方案数,简写为(i,j)。那么我们给出完整的递推:

我们说明一下,比如第一行向第二行递推的时候,(1,1)可以向(2,2)递推的为什么我们不连呢?因为我们在第一行计算(2,2)时,就已经计算了从(1,1)转移过来的情况了。所以第一行除了向(5,0)(5,1)(5,2)连边外,其他的直接连下来。现在,有木有发现第一行有三个状态自始至终都没有用到,(1,1)(2,1)(3,1),为什么?其实我们以后能够到的只是可以递推到大于等于5的,而最有可能的(3,1)也只能递推到4,即后面加一个0或者2,所以我们可以将这些冗余状态删除。完了,就成这样了:

这样当n=6时,也只有100个状态,而不是开始的6*5*5=150个状态。比如计算n=6,m=1000,只有计算出a=a^(m-25)(a为转移矩阵),然后用S[i,j]这个数组,就是从S[1,0]到S[4,2]共9个元素,分别乘以a的最后(n-1)列?为什么不是n列呢?因为我们上面说转换为以0结尾,所以最后不能以0结尾。

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <map>

#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)>=0?(x):-(x))
#define i64 long long
#define u32 unsigned int
#define u64 unsigned long long
#define clr(x,y) memset(x,y,sizeof(x))
#define CLR(x) x.clear()
#define ph(x) push(x)
#define pb(x) push_back(x)
#define Len(x) x.length()
#define SZ(x) x.size()
#define PI acos(-1.0)
#define sqr(x) ((x)*(x))
#define MP(x,y) make_pair(x,y)

#define FOR0(i,x) for(i=0;i<x;i++)
#define FOR1(i,x) for(i=1;i<=x;i++)
#define FOR(i,a,b) for(i=a;i<=b;i++)

#define rush() int CC;for(scanf("%d",&CC);CC--;)
#define Rush(n)  while(scanf("%d",&n)!=-1)
using namespace std;

void RD(int &x){scanf("%d",&x);}
void RD(i64 &x){scanf("%I64d",&x);}
void RD(u32 &x){scanf("%u",&x);}
void RD(double &x){scanf("%lf",&x);}
void RD(int &x,int &y){scanf("%d%d",&x,&y);}
void RD(i64 &x,i64 &y){scanf("%I64d%I64d",&x,&y);}
void RD(u32 &x,u32 &y){scanf("%u%u",&x,&y);}
void RD(double &x,double &y){scanf("%lf%lf",&x,&y);}
void RD(int &x,int &y,int &z){scanf("%d%d%d",&x,&y,&z);}
void RD(i64 &x,i64 &y,i64 &z){scanf("%I64d%I64d%I64d",&x,&y,&z);}
void RD(u32 &x,u32 &y,u32 &z){scanf("%u%u%u",&x,&y,&z);}
void RD(double &x,double &y,double &z){scanf("%lf%lf%lf",&x,&y,&z);}
void RD(char &x){x=getchar();}
void RD(char *s){scanf("%s",s);}
void RD(string &s){cin>>s;}

void PR(int x) {printf("%d\n",x);}
void PR(int x,int y) {printf("%d %d\n",x,y);}
void PR(i64 x) {printf("%I64d\n",x);}
void PR(u32 x) {printf("%u\n",x);}
void PR(double x) {printf("%.3lf\n",x);}
void PR(char x) {printf("%c\n",x);}
void PR(char *x) {printf("%s\n",x);}
void PR(string x) {cout<<x<<endl;}

const i64 inf=((i64)1)<<60;
const double dinf=1e50;
const int INF=1000000000;
const int N=1005;

int M;

class Matrix
{
public:
    u32 a[160][160];

void init(int x)
    {
        int i,j;
        FOR0(i,M) FOR0(j,M) a[i][j]=0;
        if(x==1)
        {
            FOR0(i,M) a[i][i]=1;
        }
    }

Matrix operator*(Matrix p)
    {
        Matrix ans;
        ans.init(0);
        int i,j,k;
        FOR0(k,M) FOR0(i,M) FOR0(j,M)
        {
            ans.a[i][j]+=a[i][k]*p.a[k][j];
        }
        return ans;
    }

Matrix Pow(int n)
    {
        Matrix ans,p=*this;
        ans.init(1);
        while(n)
        {
            if(n&1) ans=ans*p;
            p=p*p;
            n>>=1;
        }
        return ans;
    }

void print()
    {
        puts("");
        int i,j;
        FOR0(i,M)
        {
            FOR0(j,M) printf("%u ",a[i][j]);
            puts("");
        }
        puts("");
    }
};

Matrix a;
int n,m;
int f[26][6],b[26][6],c[120];

int DFS(int sum,int pre)
{
    if(sum==0) return 1;
    if(sum<0) return 0;
    if(f[sum][pre]!=-1) return f[sum][pre];
    int ans=0,i;
    FOR0(i,n) if(i!=pre) ans+=DFS(sum-sqr(i-pre),i);
    return f[sum][pre]=ans;
}

int OK(int i,int j)
{
    int k;
    FOR0(k,n) if(k!=j&&i+sqr(j-k)>=(n-1)*(n-1)+1) return 1;
    return 0;
}

void initMatrix()
{
    clr(f,-1); clr(b,0);
    int i,j,k,X=(n-1)*(n-1);
    M=0;
    FOR1(i,X) FOR0(j,n) if(OK(i,j))
    {
        c[M]=DFS(i,j);
        b[i][j]=M++;
    }
    a.init(0);
    int x,y;
    FOR0(i,n) FOR0(j,n) if(i!=j)
    {
        x=b[X+1-sqr(i-j)][j];
        y=b[X][i];
        a.a[x][y]++;
    }
    for(i=2;i<=X;i++) FOR0(j,n) if(OK(i-1,j))
    {
        x=b[i][j];
        y=b[i-1][j];
        a.a[x][y]++;
    }
}

int main()
{
    int num=0;
    rush()
    {
        RD(n,m);
        printf("Case %d: ",++num);
        if(n==2)
        {
            puts("1");
            continue;
        }
        initMatrix();
        u32 ans=0;
        int i,j;
        if(m<=(n-1)*(n-1))
        {
            FOR1(i,n-1) ans+=DFS(m,i);
            PR(ans);
            continue;
        }
        a=a.Pow(m-(n-1)*(n-1));
        FOR0(i,M) for(j=M-n+1;j<M;j++) ans+=c[i]*a.a[i][j];
        PR(ans);
    }
}

lightOJ 1172 Krypton Number System(矩阵+DP)的更多相关文章

  1. UVa 11651 Krypton Number System DP + 矩阵快速幂

    题意: 有一个\(base(2 \leq base \leq 6)\)进制系统,这里面的数都是整数,不含前导0,相邻两个数字不相同. 而且每个数字有一个得分\(score(1 \leq score \ ...

  2. Poj 2411 Mondriaan's Dream(压缩矩阵DP)

    一.Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, ...

  3. hdu4975 网络流解方程组(网络流+dfs判环或矩阵DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=4975 A simple Gaussian elimination problem. Time Limit: 20 ...

  4. Find n‘th number in a number system with only 3 and 4

    这是在看geeksforgeeks时看到的一道题,挺不错的,题目是 Given a number system with only 3 and 4. Find the nth number in th ...

  5. Moduli number system

    A number system with moduli is defined by a vector of k moduli, [m1,m2, ···,mk]. The moduli must be p ...

  6. F - The Fun Number System(第二季水)

    Description In a k bit 2's complement number, where the bits are indexed from 0 to k-1, the weight o ...

  7. hdu 4975 最大流问题解决队伍和矩阵,利用矩阵dp优化

    //刚開始乱搞. //网络流求解,假设最大流=全部元素的和则有解:利用残留网络推断是否唯一, //方法有两种,第一种是深搜看看是否存在正边权的环.见上一篇4888 //至少四个点构成的环,另外一种是用 ...

  8. The Stern-Brocot Number System(排序二进制)

    The Stern-Brocot Number System Input: standard input Output: standard output The Stern-Brocot tree i ...

  9. POJ 1023 The Fun Number System

    Description In a k bit 2's complement number, where the bits are indexed from 0 to k-1, the weight o ...

随机推荐

  1. mysql语句大全

    转自:http://www.cnblogs.com/yunf/archive/2011/04/12/2013448.html   1.说明:创建数据库 CREATE DATABASE database ...

  2. JavaScript Tutorial

    JavaScript Tutorial http://javascript.info/root Object.create rabit.hasOwnProperty('eats') Object.ge ...

  3. Linux课本第一二章

    一.第一章:Linux内核简介 1.操作系统和内核:操作系统是指在整个系统中负责完成最基本功能和系统管理的那些部分,包括内核.设备驱动程序.启动引导程序.命令行shall等. 内核就是操作系统的核心, ...

  4. WPF 多线程处理(3)

    WPF 多线程处理(1) WPF 多线程处理(2) WPF 多线程处理(3) WPF 多线程处理(4) WPF 多线程处理(5) WPF 多线程处理(6) 首先我们需要几个属性来保存取得的数据,因为在 ...

  5. android 自定义ratingbar 图片显示不全的解决方案

    在res/style中自定义评分条: <!-- 自定义评分条 --> <style name="roomRatingBar" parent="@andr ...

  6. emulatorarm.exe已停止工作

    今天使用ADT 打开android模拟器突然发现模拟器报错,[emulatorarm.exe已停止工作],昨天还是好好的,不知道为什么,重建新的模拟器还是这样. 解决办法: 更改ram大小为 512M ...

  7. C++拷贝构造函数详解(转载)

    一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员 ...

  8. 使用Putty连接VirtualBox的Ubuntu

    从vbox中安装了ubuntu server,然后用ssh连过去,发现有一个错误:server unexpectedly closed network connection.猛然发现,ssh没有安装. ...

  9. 1833: [ZJOI2010]count 数字计数 - BZOJ

    Description给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次.Input输入文件中仅包含一行两个整数a.b,含义如上所述.Output输出文件中包含一 ...

  10. git Clone SSL certificate problem: self signed certificate

    自己的git服务器遇到证书是自签的,git验证后会拒绝,此时,采用如下命令临时禁用就好 git -c http.sslVerify=false clone https://domain.com/pat ...