1.状态机
P1353 [USACO08JAN] Running S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<iostream>
#include<map>
#include<cstring>
using namespace std;
#define int long long
#define inf 0x7ffffffffffffff
#define endl "\n"
const int N = 1e6 + 7;
const int mod = 1e9 + 7;
int dp[101100][1010];
int Time[1010][1010];
int a[N], b[N], c[N];
class solve {
public:
static void solution() {
int n, m;
cin >> n >> m ;
for ( int i = 1 ; i <= n ;i ++)
{
cin >> a[i];
}
dp[1][0] = 0;
dp[1][1] = a[1];
for(int i = 1; i <= n ;i ++ )
{
dp[i][0] = max(dp[i-1][0],dp[i][0]);
for(int j = 1 ; j <= min(m , i) ;j ++)
{
dp[i][j] = max(dp[i][j] , dp[i-1][j-1] + a[i]);
dp[i+j][0] = max(dp[i][j],dp[i+j][0]);
}
}
cout << dp[n][0] << endl;
}
};
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
// cin >> T;
while (T--) {
solve::solution();
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL mod = 2000120420010122;
LL dp[5];
int main() {
ios::sync_with_stdio(0);
string s;
while (cin >> s) {
for(int i = 1;i <= 4;i ++){
dp[i] = 0;
}
for (int i = 0; i < s.size(); i++) {
s[i] = tolower(s[i]);
dp[1] = (dp[1] + (s[i] == 'c')) % mod;
dp[2] = ((dp[2] + (s[i] == 'w') * dp[1])) % mod;
dp[3] = ((dp[3] + (s[i] == 'b') * dp[2])) % mod;
dp[4] = ((dp[4] + (s[i] == 'c') * dp[3])) % mod;
}
cout << dp[4] % mod << '\n';
}
return 0;
}
2 .状压dp
P1896 [SCOI2005] 互不侵犯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
#define ll long long
#define endl "\n"
typedef long long LL;
const int N = 12, M = 1 << 10, K = 110;
int n, m;
vector<int> state;
int cnt[M];
vector<int> head[M];
LL f[N][K][M];
bool check(int state)
{
for(int i = 0 ; i < n ;i ++)
{
if((state >> i & 1) & (state >> (i + 1) & 1 ))
return false;
}
return true;
}
int count(int state)
{
int res = 0 ;
for(int i = 0 ; i < n ;i ++)
{
res += state >> i & 1;
}
return res;
}
int main() {
scanf("%d%d", &n, &m);
//筛选合法状态
for(int i = 0 ; i < 1 << n ;i ++)
{
if(check(i))
{
state.push_back(i);
cnt[i] = count(i);
}
}
//合法转移
int len = state.size();
//cout << len ;
for(int i = 0 ; i < len; i ++)
{
for(int j = 0; j < len ;j ++)
{
int a = state[i] , b = state[j];
if((a & b)==0&&check(a | b))
{
head[i].push_back(j);
//cout <<head[i].size()<<" ";
}
}
}
f[0][0][0] = 1;
for(int i = 1 ; i <= n + 1 ;i++)
{
for(int j = 0 ;j <= m ;j++)
{
for(int a = 0 ; a < len ; a++)
{
for(int b : head[a])
{
int c = cnt[state[a]];
if(j >= c)
f[i][j][a] += f[i-1][j-c][b];
}
}
}
}
cout << f[n+1][m][0] << endl;
return 0;
}
P2704 [NOI2001] 炮兵阵地 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
#define PII pair<int,int>
#define ll long long
const int N=110;
const int M=1<<10;
int n,m;
char a[N][N];
int dp[2][M][M];
int g[N];//这一行炮兵的位置是否合法
vector<int> state;
int cnt[M];
//合法筛选,一行内相邻的1必须间隔2个
bool check(int state)
{
for(int i = 0 ;i < m;i++)
{
if((state >> i & 1)&&((state >> (i + 1) & 1)||(state >> (i + 2) & 1)))
return false;
}
return true;
}
//查询1的个数
int count(int state)
{
int res=0;
for(int i=0;i<m;i++)
{
res+= state>>i & 1;
}
return res;
}
int main()
{
cin>>n >>m;
//输入
for(int i=1;i<=n;i++)
{
for(int j=0;j<m;j++)
{
cin>>a[i][j];
if(a[i][j]=='H')//把H用1来代替,方便后面计算
g[i] += 1 << j;
}
}
//筛选一行合法状态
for(int i= 0 ;i< 1<<m;i++)
{
if(check(i))
{
state.push_back(i);
cnt[i] = count(i);
}
}
//筛选可以转移的合法状态
int len = state.size();
dp[0][0][0] = 0;
for(int i=1 ;i <=n+2;i ++)
{
for(int j= 0 ;j<len ;j++)
{
for(int k = 0 ; k <len ; k++)
{
for(int u = 0 ;u <len ; u ++)
{
int a = state[j] , b = state[k] ,c = state[u];
if((a&b)|(b&c)|(a&c)) continue;
if((g[i] & b )| (g[i-1] & a)) continue;
dp[i&1][j][k] = max(dp[i&1][j][k],dp[(i-1)&1][u][j] + cnt[b]);
}
}
}
}
cout << dp[(n+2)&1][0][0] <<endl;
return 0;
}
P2831 [NOIP2016 提高组] 愤怒的小鸟 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define x first
#define y second
using namespace std;
typedef pair<double, double> PDD;
const int N = 18, M = 1 << 18;
const double eps = 1e-8;
int n, m;
PDD q[N];
int path[N][N];
int f[M];
int cmp(double x, double y)
{
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
int main()
{
int T;
cin >> T;
while (T -- )
{
cin >> n >> m;
for (int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
memset(path, 0, sizeof path);
for (int i = 0; i < n; i ++ )
{
path[i][i] = 1 << i;
for (int j = 0; j < n; j ++ )
{
double x1 = q[i].x, y1 = q[i].y;
double x2 = q[j].x, y2 = q[j].y;
if (!cmp(x1, x2)) continue;
double a = (y1 / x1 - y2 / x2) / (x1 - x2);
double b = y1 / x1 - a * x1;
if (cmp(a, 0) >= 0) continue;
int state = 0;
for (int k = 0; k < n; k ++ )
{
double x = q[k].x, y = q[k].y;
if (!cmp(a * x * x + b * x, y)) state += 1 << k;
}
path[i][j] = state;
}
}
memset(f, 0x3f, sizeof f);
f[0] = 0;
for (int i = 0; i + 1 < 1 << n; i ++ )
{
int x = 0;
for (int j = 0; j < n; j ++ )
if (!(i >> j & 1))
{
x = j;
break;
}
for (int j = 0; j < n; j ++ )
f[i | path[x][j]] = min(f[i | path[x][j]], f[i] + 1);
}
cout << f[(1 << n) - 1] << endl;
}
return 0;
}
3 . 数位dp
P8764 [蓝桥杯 2021 国 BC] 二进制问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#define int long long
#define pii pair<int,int>
#define endl "\n"
#define IL inline
using namespace std;
const int N = 1e6 + 10;
const int mod= 1e9+7;
int n, m;
int jc[100];
IL void init()
{
int sum = 1;
jc[0] = 1;
for(int i=1; i<= 100 ; i ++)
{
sum *= i;
jc[i] = sum ;
}
}
int C(int b, int a) // 计算组合(b在下面,a在上面)
{
int sum = 1;
for (int i = b, j = 1; j <= a; i--, j++)
sum = sum * i / j;
return sum;
}
IL void solve()
{
vector<int> nums;
while(n) nums.push_back(n%2) , n /= 2;
int len = nums.size();
int res = 0 ;
int last = 0 ; // 一的个数
for(int i = len - 1 ; i >= 0 ; i --)
{
if(nums[i]==1)
{
if((m - last) >= 0 )
res += C(i , m - last);
last ++;
}
// cout << res << '\n';
if(last > m)
break;
if(last == m && !i)
res ++;
}
cout << res ;
}
signed main()
{
init();
cin >> n >> m;
solve();
return 0;
}
P4317 花神的数论题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define endl "\n"
#define IL inline
using namespace std;
const int N = 1e6 + 10;
const int mod= 1e7 + 7; ;
int C[110][110];
class solve{
public:
//快速幂
static int qmi(int x,int y)
{
int res = 1 ;
while(y)
{
if(y & 1)
res = res * x % mod ;
y >>= 1;
x = x * x % mod;
}
return res ;
}
//求解组合数
static void init()
{
//防止数组越界
C[0][0] = 1;
for( int i = 1 ;i <= 100 ; i ++)
{
C[i][0] = 1;
C[i][1] = i;
}
for(int i = 2 ; i <= 100 ; i ++)
{
for(int j = 2 ; j <= i ; j ++)
{
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]);
}
}
}
static void solution()
{
int n ;
cin >> n;
vector<int> nums ;
vector<int> answered(100);
answered.clear();
while(n) nums.push_back(n & 1) , n >>= 1;
int last = 0;//记录出现了多少个一
int answer = 1 ;// 答案
int len = nums.size() ;
for(int i = len - 1 ; i >= 0; i --)
{
int x = nums[i] ;
if(x)
{
for(int j = 0; j <= i ; j ++)
{
answered[j + last] += C[i][j];
}
}
if(x == 1)
last ++;
}
//求解答案
answered[last] ++;
for(int i = 1 ;i <= len ; i ++)
{
if(answered[i])
{
answer = answer * qmi(i , answered[i]) % mod;
}
}
//cout << answer << endl;
cout << answer << endl;
}
};
signed main()
{
int T = 1;
// cin >> T;
solve::init();
while(T--)
{
solve::solution();
}
return 0;
}
P1836 数页码 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define ll long long
#define PII pair<int,int>
#define endl "\n"
const int N = 30;
int a[N];
ll f[N][10];
//快速幂
ll qmi(int x,int y)
{
ll res = 1;
while(y)
{
if(y & 1)
res = res * x;
x = x * x;
y >>= 1;
}
return res;
}
//预处理
void init()
{
for(int i = 1 ; i <= N ; i ++)
{
for(int j = 0 ;j <= 9 ; j ++)
{
if(j==0)
{
f[i][0] = f[i-1][9];
}else
{
f[i][j] = f[i][j-1] + (f[i][0] + qmi(10,i-1)*j);
}
}
}
}
ll get(ll x)
{
ll res=0;
vector<int> v;
int num=x;
while(num) v.push_back(num%10),num/=10;
//比如是7264
for(int i = v.size()- 1 ;i >= 0; i--)
{
if(v[i] == 0)
continue;
res += f[i + 1][v[i]-1]; // 拆成1 - 6999 和 7000 - 7264
res += (x%qmi(10,i)+1)*v[i]; // 第一次循环,这里是算7000 - 7264 中7的个数
}
return res;
}
int main()
{
init();
int n ;
cin >> n ;
cout << get(n);
return 0;
}
P2657 [SCOI2009] windy 数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define ll long long
#define PII pair<int,int>
#define endl "\n"
const int N = 11;
const int mod= 1e9+7;
ll 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];
}
}
}
}
}
ll dp(ll p)
{
if(!p) return 0;
ll res=0;
vector<int> v;
ll num=p;
while(num) v.push_back(num%10),num/=10;
int last = -2;
for(int i = v.size() -1 ;i >= 0 ; i--)
{
int x = v[i];
for(int j = i == v.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 < v.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;
}
P2602 [ZJOI2010] 数字计数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 14
#define LL long long
LL dp[maxn][10][10];
LL L,R;
LL ans[10][2];
int a[maxn],num;
inline LL quick(LL a,LL b)
{
LL s=1;
while(b)
{
if(b&1) s*=a;
b>>=1;
a*=a;
}
return s;
}
inline void slove(LL x,int pd)
{
memset(dp,0,sizeof(dp));
num=0;
memset(a,0,sizeof(a));
while(x)
{
a[++num]=x%10;
x/=10;
}//分解数位
for(re int i=0;i<=9;i++) dp[1][i][i]=1;//初始化
for(re int i=2;i<=num;i++)//枚举位数
for(re int j=0;j<=9;j++)//当前最高位
{
for(re int k=0;k<=9;k++)//次高位
{
for(re int p=0;p<=9;p++)
dp[i][j][p]+=dp[i-1][k][p];
}
dp[i][j][j]+=quick(10,i-1);//乘法原理
}
for(re int i=1;i<num;i++)//位数比x小的,一定能够满足条件
for(re int j=1;j<=9;j++)//不能有前导零
for(re int k=0;k<=9;k++)
ans[k][pd]+=dp[i][j][k];
for(re int i=1;i<a[num];i++)//位数相同,但最高位比x小
for(re int k=0;k<=9;k++)
ans[k][pd]+=dp[num][i][k];
for(re int i=num-1;i>=1;i--)//当前不同的那一位,[i+1,num]与x完全相同
{
for(re int j=0;j<a[i];j++)//不同的这一位也必须必对应x位置上的数小
{
for(re int k=0;k<=9;k++)
ans[k][pd]+=dp[i][j][k];
}
for(re int p=num;p>i;p--)
ans[a[p]][pd]+=a[i]*quick(10,i-1);
//由于我们保证[i+1,num]相同,那么这些数码也应该计入答案,于是还是一个乘法原理
}
//但是这个dp全程都不能处理出x是否满足条件
//因为最后也只是判断第一位上的数比给定数的第一位小
//所以slove(x)其实求得是[0,x)满足条件的数的个数
}
int main()
{
scanf("%lld%lld",&L,&R);
slove(R+1,0),slove(L,1);
for(re int i=0;i<=9;i++)
printf("%lld ",ans[i][0]-ans[i][1]);
putchar(10);
return 0;
}