acwing提高數位dp
阿新 • • 發佈:2022-03-22
度的數量
思路:
樣例輸入:
15 20
2
2
樣例輸出:
3
程式碼模板:
//取K個1 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N = 100; int f[N][N]; //0不選 1選 int k,b; void init(){ for(int i=0;i<N;i++) for(int j=0;j<=i;j++) if(!j) f[i][j]=1; else f[i][j]=(f[i-1][j]+f[i-1][j-1]); } int dp(int x) { vector<int> num; while(x) { num.push_back(x%b); x/=b; } int res=0,last=k; for(int i=num.size()-1;i>=0;i--) { x=num[i]; if(x) //左子樹 { res+=f[i][last];//不選的組合數 if(x>1){ //某數的b進制中有x>1 由於題目條件無法表示該數 if (last - 1 >= 0) res += f[i][last - 1];//當前位選為1的組合數 break; }else{ last--; if(last<0) break; } } if(last==0&&i==0)// 最右側分支上的方案 { res++; } } return res; } int main(){ int x,y; init(); cin>>x>>y>>k>>b; cout<<dp(y)-dp(x-1)<<endl;; return 0; }
陣列遊戲
樣例輸入:
1 9
1 19
樣例輸出:
9
18
程式碼模板:
//不下降序列 #include <cstring> #include <iostream> #include <algorithm> #include <vector> using namespace std; const int N = 15; int f[N][N]; // f[i, j]表示一共有i位,且最高位填j的數的個數 void init() { for (int i = 0; i <= 9; i ++ ) f[1][i] = 1; for (int i = 2; i < N; i ++ ) for (int j = 0; j <= 9; j ++ ) for (int k = j; k <= 9; k ++ ) f[i][j] += f[i - 1][k]; } int dp(int n) { if (!n) return 1; vector<int> nums; while (n) nums.push_back(n % 10), n /= 10; int res = 0; int last = 0; for (int i = nums.size() - 1; i >= 0; i -- ) { int x = nums[i]; for (int j = last; j < x; j ++ ) res += f[i + 1][j]; if (x < last) break; last = x; if (!i) res ++ ; } return res; } int main() { init(); int l, r; while (cin >> l >> r) cout << dp(r) - dp(l - 1) << endl; return 0; }
Windy數
思路
樣例輸入:
25 50
樣例輸出:
20
程式碼模板:
//相鄰數之差>=2 #include <cstring> #include <iostream> #include <algorithm> #include <vector> using namespace std; const int N = 11; int f[N][10]; void init() { for (int i = 0; i <= 9; i ++ ) f[1][i] = 1; for (int i = 2; i < N; i ++ ) for (int j = 0; j <= 9; j ++ ) for (int k = 0; k <= 9; k ++ ) if (abs(j - k) >= 2) f[i][j] += f[i - 1][k]; } int dp(int n) { if (!n) return 0; vector<int> nums; while (n) nums.push_back(n % 10), n /= 10; int res = 0; int last = -2; for (int i = nums.size() - 1; i >= 0; i -- ) { int x = nums[i]; for (int j = i == nums.size() - 1; j < x; j ++ ) if (abs(j - last) >= 2) res += f[i + 1][j]; if (abs(x - last) >= 2) last = x; else break; if (!i) res ++ ; } // 特殊處理有前導零的數 for (int i = 1; i < nums.size(); i ++ ) for (int j = 1; j <= 9; j ++ ) res += f[i][j]; return res; } int main() { init(); int l, r; cin >> l >> r; cout << dp(r) - dp(l-1)<< endl; return 0; }
數字遊戲II
樣例輸入:
1 19 9
樣例輸出:
2
程式碼模板:
//num mod N = 0
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 11, M = 110;
int P;
int f[N][10][M];//一共有i位 最高位是j 餘數是k
int mod(int x, int y) //解決取模負數
{
return (x % y + y) % y;
}
//打表
void init()
{
memset(f, 0, sizeof f);
for (int i = 0; i <= 9; i ++ ) f[1][i][i % P] ++ ;
for (int i = 2; i < N; i ++ ) //當前第i位
for (int j = 0; j <= 9; j ++ ) //當前位是j
for (int k = 0; k < P; k ++ ) //餘數是k
for (int x = 0; x <= 9; x ++ ) //上一位是x
f[i][j][k] += f[i - 1][x][mod(k - j, P)];
}
int dp(int n)
{
if (!n) return 1;
vector<int> nums;
while (n) nums.push_back(n % 10), n /= 10;
int res = 0;
int last = 0;
for (int i = nums.size() - 1; i >= 0; i -- )
{
int x = nums[i];
for (int j = 0; j < x; j ++ )
res += f[i + 1][j][mod(-last, P)];
last += x;
if (!i && last % P == 0) res ++ ;
}
return res;
}
int main()
{
int l, r;
while (cin >> l >> r >> P)
{
init();
cout << dp(r) - dp(l - 1) << endl;
}
return 0;
}