比赛的时候规律题是很常见的事情 ,所以这里做下总结。

解题分几个步骤;

1 : 首先规律题的数据规模是大的 , 可以说如果结果是数字样的话,而且数据大很有可能的规律;

 

2 : 暴力打表找到前面10位数字;

2(1)  :  如果足够强大可以根据某种灵性的解法得出答案(我是不够灵的。。)

 

3 :如果足够强大可以暴力推出公式;

3(1) : 运用技巧性得出结果

 

4:运用矩阵快速幂

 

例如: HDU 6185

用没有数量限制2×1和1×2的矩形去铺一块4×n的矩形,有多少种方法

n最大1e^18

  1: 打出暴力程序(参考状态压缩DP瓷砖覆盖):

*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef long long LL;
using namespace std;
 
const int MAX=(1<<11)+10;
int n,m;
LL temp[MAX],dp[MAX],bin[15];
bool mark[MAX];
 
bool check(int i){
    while(i){
        if(i&1){
            i>>=1;
            if(!(i&1))return false;//第j列是1则第j+1列必须是1 
            i>>=1;//继续判断下一列 
        }else i>>=1;//继续判断下一列 
    }
    return true;
}
 
void Init(){
    memset(mark,false,sizeof mark);
    memset(temp,0,sizeof temp);
    for(int i=0;i<bin[m];++i){//初始化第一行和可以到达什么状态 
        if(check(i))temp[i]=1,mark[i]=true;
    }
}
 
void DP(){
    for(int k=2;k<=n;++k){
        for(int i=0;i<bin[m];++i)dp[i]=0;
        for(int i=0;i<bin[m];++i){
            for(int j=0;j<bin[m];++j){
                if((i|j) != bin[m]-1)continue;//每一位或之后必须每一位是1(综合前面3种情况和分析可知)
                if(!mark[i&j])continue;//由初始化和前面分析三种情况分析可知i&j必须得到和初始化可以到达的状态一样才行
                dp[i]+=temp[j];//i可以从j到达,则增加j的方案数 
            }
        }
        for(int i=0;i<bin[m];++i)temp[i]=dp[i];
    }
}
 
int main(){
    bin[0]=1;
    for(int i=1;i<12;++i)bin[i]=2*bin[i-1];
    while(~scanf("%d%d",&n,&m),n+m){
        if(n<m)swap(n,m);//始终保持m<n,提高效率 
        Init();
        DP();
        printf("%lld\n",temp[bin[m]-1]);//输出最后一行到达时的状态必须全部是1 
    }
    return 0;
}
View Code

相关文章:

  • 2021-12-16
  • 2022-12-23
  • 2021-12-29
  • 2022-02-08
  • 2021-12-04
  • 2021-12-26
  • 2021-06-19
猜你喜欢
  • 2021-10-19
  • 2022-12-23
  • 2022-01-22
  • 2022-12-23
  • 2021-12-10
  • 2021-05-17
  • 2022-02-08
相关资源
相似解决方案