hihocoder 1048 压状DP
2018-03-09 19:20
281 查看
hihocoder 1048 做了很久但是2ms压着点过。太慢了。
再来看看能不能缩短点时间。
在网上查了下大佬们的代码。如果还要精简就是改转移方程式了。
改变了下方法。因为这个不是很大。1000*(1<<5)。可以开二维数组完整存。
再加上记忆化搜索。应该就可以缩短时间了。最后也的确1ms过了。emmmm
然后看了HDU 6185 ,也就是去年广西邀请赛的一题了。类似。不过别人是1E18的n肯定会跑超时了。怎么办呢。emmmmmm肯定是规律了。不过我找不到规律,- -,然后找了下大佬们的思路。用高斯消元法推出来的。做笔记,画重点。先给高斯模板上上来,好东西啊!
这里得到了矩阵的系数了。然后就是矩阵快速幂了。
注:关于HDU 6185题,来源于:http://blog.csdn.net/d12155214552/article/details/77751796
再来看看能不能缩短点时间。
#include<bits/stdc++.h> #define INF 1e18 #define inf 1e9 #define min(a,b) a<b?a:b #define max(a,b) a>b?a:b #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define IOS ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std ; typedef long long ll; typedef unsigned long long ull; const int _max = 1005; const ll mod = 1000000007; ll dp[2][1<<5]; int n,m,tmp; bool flag; bool check(int tmp){ int c = 0; while(tmp){ if(tmp&1){ if(c == 0) c++; else c = 0; } else if(c == 1) return false; tmp>>=1; } if(c) return false; return true; } int main(){ while(cin>>n>>m){ memset(dp,0,sizeof(dp)); tmp = 1<<m; dp[0][tmp-1] = 1; flag = true; for(int i = 0 ; i < n ; i++){ for(int sta = 0 ; sta < tmp ; sta++) dp[flag][sta] = 0; for(int sta1 = 0 ; sta1 < tmp ; sta1++){ int tmp1 = sta1^(tmp-1); // cout<<sta1<<' '<<tmp1<<endl; for(int sta2 = tmp1 ; sta2 < tmp ; sta2++){ // cout<<sta1<<' '<<sta2<<' '<<((sta2&tmp1)==tmp1)<<' '; if((sta2&tmp1) != tmp1) continue; int tmp2 = sta2^tmp1; // cout<<check(tmp2)<<endl; if(!check(tmp2)) continue; // cout<<sta1<<' '<<sta2<<endl; dp[flag][sta2] = (dp[flag][sta2]+dp[!flag][sta1])%mod; } // cout<<"----------"<<endl; } flag = !flag; } cout<<dp[!flag][tmp-1]<<endl; } return 0; }
在网上查了下大佬们的代码。如果还要精简就是改转移方程式了。
改变了下方法。因为这个不是很大。1000*(1<<5)。可以开二维数组完整存。
再加上记忆化搜索。应该就可以缩短时间了。最后也的确1ms过了。emmmm
#include<bits/stdc++.h> #define INF 1e18 #define inf 1e9 #define min(a,b) a<b?a:b #define max(a,b) a>b?a:b #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define IOS ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std ; typedef long long ll; typedef unsigned long long ull; const int _max = 1005; const ll mod = 1000000007; int n,m,tmp; ll dp[_max][1<<5]; bool check(int tmp){ int c = 0; while(tmp){ if(tmp&1){ if(c == 0) c++; else c = 0; } else if(c == 1) return false; tmp>>=1; } if(c) return false; return true; } int dfs(int i,int sta1){ if(i == n) return (sta1==(tmp-1)); if(dp[i][sta1] != -1) return dp[i][sta1]; int cnt = 0; int tmp1 = sta1^(tmp-1); for(int sta2 = tmp1 ; sta2 < tmp ; sta2++){ if((sta2&tmp1) != tmp1) continue; int tmp2 = sta2^tmp1; if(!check(tmp2)) continue; cnt = (cnt+dfs(i+1,sta2))%mod; } dp[i][sta1] = cnt; return cnt; } void init(){ tmp = (1<<m); memset(dp,-1,sizeof(dp)); } int main(){ IOS; while(cin>>n>>m){ init(); cout<<dfs(0,tmp-1)<<endl; } return 0; }
然后看了HDU 6185 ,也就是去年广西邀请赛的一题了。类似。不过别人是1E18的n肯定会跑超时了。怎么办呢。emmmmmm肯定是规律了。不过我找不到规律,- -,然后找了下大佬们的思路。用高斯消元法推出来的。做笔记,画重点。先给高斯模板上上来,好东西啊!
//f(n)=f(n-1)*a+f(n-2)*b+f(n-3)*c+f(n-4)*d情况下的高斯消元 #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <cstring> #include <vector> using namespace std; const int maxn=105; typedef double Matrix[maxn][maxn]; Matrix A,S; //n是方程的个数 void gauss(Matrix A,int n) { int i,j,k,r; for(int i=0; i<n; i++) { r=i; for( j=i+1; j<n; j++) if(fabs(A[j][i])>fabs(A[r][i]))r=j; if(r!=i) for(j=0; j<=n; j++)swap(A[r][j],A[i][j]); for(k=i+1; k<n; k++) { double f=A[k][i]/A[i][i]; for(j=i; j<=n; j++) A[k][j]-=f*A[i][j]; } } for(i=n-1; i>=0; i--) { for(j=i+1; j<n; j++) A[i] -=A[j] *A[i][j]; A[i] /=A[i][i]; } } int main() { memset(A,0,sizeof(A)); A[0][0]=95,A[0][1]=36,A[0][2]=11,A[0][3]=5,A[1][0]=6336,A[1][1]=2245,A[1][2]=781; A[1][3]=281,A[2][0]=781,A[2][1]=281,A[2][2]=95,A[2][3]=36,A[3][0]=2245,A[3][1]=781; A[3][2]=281,A[3][3]=95,A[0][4]=281,A[1][4]=18061,A[2][4]=2245,A[3][4]=6336; gauss(A,4); for(int i=0; i<4; i++) { printf("%8.2f\n",A[i][4]); } return 0; }
这里得到了矩阵的系数了。然后就是矩阵快速幂了。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #define ll long long using namespace std; ll mod=1000000007; struct Matrix { ll a[4][4]; }; Matrix multi(Matrix x,Matrix y) { Matrix ans; for(int i=0; i<4; i++) for(int j=0; j<4; j++) { ans.a[i][j]=0; for(int k=0; k<4; k++) ans.a[i][j]=(ans.a[i][j]+x.a[i][k]*y.a[k][j]+mod)%mod; } return ans; } Matrix mqmod(ll l) { Matrix p,q; memset(p.a,0,sizeof(p.a)); p.a[0][0]=p.a[0][2]=p.a[1][0]=p.a[2][1]=p.a[3][2]=1; p.a[0][1]=5;p.a[0][3]=-1; for(int i=0; i<4; i++) for(int j=0; j<4; j++) q.a[i][j]=(i==j); while(l) { if(l&1)q=multi(q,p); p=multi(p,p); l>>=1; } return q; } int main() { ll n; while(~scanf("%I64d",&n)) { if(n==1) { printf("1\n"); continue; } else if(n==2) { printf("5\n"); continue; } else if(n==3) { printf("11\n"); continue; } else if(n==4) { printf("36\n"); continue; } else { ll num=0; Matrix ans; ans=mqmod(n-4); num=(ans.a[0][0]*36+ans.a[0][1]*11+ans.a[0][2]*5+ans.a[0][3])%mod; num=(num+mod)%mod; printf("%I64d\n",num); } } return 0; }
注:关于HDU 6185题,来源于:http://blog.csdn.net/d12155214552/article/details/77751796
相关文章推荐
- [hihocoder]:1048 状态压缩二(状压DP)
- 状压DP——hihoCoder 1048
- hihocoder-1048 状态压缩·二(状压DP)
- 【日常学习】【区间DP】codevs1048 石子归并题解
- DP 之 CODE[VS] 1048 石子归并 (两种实现方式:递归,循环)
- 【codevs1048】【codevs1154&&06TG】石子归并、能量项链,序列dp的典型题目
- hihocoder 1033 交错和 (数位dp)
- Hihocoder 1044 DP状态压缩
- hihocoder 1076 与链(DP)
- 【hihocoder1290 微软2016校园招聘4月在线笔试C】【二维DP】 Demo Day 机器人遇到障碍向右走向下走 最少调整数使得左上角走到右下角
- hihocoder 1110 正则表达式 (区间dp)
- hihocoder第158周非法二进制数(dp)
- 【hihocoder [Offer收割]编程练习赛9 D】【简单DP】矩阵填数
- hihoCoder 1044 状态压缩·一 (状压dp)
- codevs 1048能量项链(区间DP)
- 2015编程之美初赛1 hihoCoder1158 质数相关 树形DP
- 【Hihocoder [Offer收割]编程练习赛10 B】【简单DP】出勤记录II
- 采药 水题 dp 01背包问题 luogu1048
- [hihocoder1063]树形DP
- hihoCoder 1044 : 状态压缩·一 状压dp