题目链接: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. 【html5】这些新类型 能提高生产力

    <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title> ...

  2. .Net webservice动态调用

    直接贴代码吧 public class PmsService { /// <summary> /// pms接口 /// </summary> /// <param na ...

  3. android 开启或者隐藏软键盘

    一. 隐藏软键盘方法一(注:此方法本人使用时发现isActivie()失效,建议还是用其他方法..): InputMethodManager imm = (InputMethodManager)get ...

  4. 所有的代码生成器都是浮云,如果可以用aspx文件作为模板

    首先申明:标题中的如果是可以去掉的. 想写这篇文章很长时间了,一来是跟大家分享一下,别浪费时间在写代码生成器上面了,什么CodeSmith,XXCodeGenerator等等,都是浮云:二来想跟大家交 ...

  5. IntelliJ IDEA 14 创建maven项目二

    前言: 在我的idea14使用maven创建web工程文章介绍了如何运用idea14创建maven项目--但有瑕疵,如下: 今天在群里交流才得知起因: 原来一直这样创建的--但结果都一样,均出现上面的 ...

  6. 【Vijos】【1164】曹冲养猪

    中国剩余定理 没啥重要的……模板题,中国剩余定理就是解出模线性方程组的一个可行解(好像也是唯一解?) 这是一种神奇的构造方法……明白了为什么这样构造是对的就行了=.=至于怎么想到这种构造方法的……去问 ...

  7. Matlab中cellfun函数的使用

    Compute the mean of each vector in cell array C. C = {1:10, [2; 4; 6], []}; averages = cellfun(@mean ...

  8. 如何将jsp中<input>设为只读

    将一个input变为只读,可以使用 readonly 属性 和 disabled 属性.  用disabled 属性时,文字显示为灰色.  下面的两种方法都是可以的: <input id =&q ...

  9. websphere变成英文了怎么变回中文

    今天进来发现,websphere在浏览器里面居然是英文的.这是因为我的浏览器少了一个中文语言设置,其实和页面编码无关. 解决办法: IE浏览器右键属性 -- internet选项 --  常规 -- ...

  10. Javascript的动态运动(1)

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...