数位dp
最好理解板子,不要硬记板子
P4999 烦人的数学作业
注意取模
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 25;
ll dp[N][200];
int a[N], len;
ll dfs(int pos, ll sum, int limit)
{
if(pos > len) return sum;
if(dp[pos][sum] != -1 && !limit) return dp[pos][sum];
ll res = 0;
int mx = limit ? a[len - pos + 1] : 9;
_for(i, 0, mx) res = (res + dfs(pos + 1, sum + i, i == mx && limit)) % mod;
if(!limit) dp[pos][sum] = res;
return res;
}
ll cal(ll x)
{
len = 0;
while(x) a[++len] = x % 10, x /= 10;
memset(dp, -1, sizeof dp);
return dfs(1, 0, 1);
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
ll l, r;
scanf("%lld%lld", &l, &r);
if(l) printf("%lld\n", (cal(r) - cal(l - 1) + mod) % mod);
else printf("%lld\n", cal(r));
}
return 0;
}
D. Meaningless Sequence
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 3000 + 10;
int n, c;
ll dp[N][N];
string s;
ll binpow(ll a, ll b)
{
ll res = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a % mod;
a = a * a % mod;
}
return res;
}
ll dfs(int pos, int cnt, int limit)
{
if(pos >= n) return binpow(c, cnt);
if(dp[pos][cnt] != -1 && !limit) return dp[pos][cnt];
ll res = 0;
int mx = limit ? (s[pos] - '0') : 1;
_for(i, 0, mx)
res = (res + dfs(pos + 1, cnt + i, i == mx && limit)) % mod;
if(!limit) dp[pos][cnt] = res;
return res;
}
ll cal()
{
memset(dp, -1, sizeof dp);
return dfs(0, 0, 1);
}
int main()
{
cin >> s >> c;
n = s.size();
printf("%lld\n", cal());
return 0;
}
P2657 [SCOI2009] windy 数
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
int dp[15][15][2], a[15], len;
int dfs(int pos, int pre, int cur, int lead, int limit)
{
if(pos > len) return cur;
if(dp[pos][pre][cur] != -1 && !lead && !limit) return dp[pos][pre][cur];
int res = 0, mx = limit ? a[len - pos + 1] : 9;
_for(i, 0, mx)
{
if(!i && lead) res += dfs(pos + 1, pre, cur, lead, i == mx && limit); //注意这里与的是limit 不要写res
else if(lead) res += dfs(pos + 1, i, cur, 0, i == mx && limit);
else res += dfs(pos + 1, i, cur && (abs(i - pre) >= 2), 0, i == mx && limit);
}
if(!lead && !limit) dp[pos][pre][cur] = res;
return res;
}
int cal(int x)
{
len = 0;
while(x) a[++len] = x % 10, x /= 10;
memset(dp, -1, sizeof dp);
return dfs(1, 0, 1, 1, 1);
}
int main()
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", cal(b) - cal(a - 1));
return 0;
}
数论模板
线性筛
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 100 + 10;
int vis[N];
vector<int> p;
void init()
{
vis[0] = vis[1] = 1;
_for(i, 2, 100)
{
if(!vis[i]) p.push_back(i);
for(int x: p)
{
if(x * i > 100) break;
vis[x * i] = 1;
if(i % x == 0) break; //注意这里i % x
} //x % i很奇怪 x是一个质数 应该是当前数是质数的倍数
}
}
int main()
{
init();
for(int x: p) printf("%d\n", x);
return 0;
}
组合数
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 30;
int c[N][N];
void init()
{
_for(i, 0, 20) c[i][0] = 1; //边界条件 注意i从0开始
_for(i, 1, 20) //从i个数中选j个
_for(j, 1, i)
c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
}
int main()
{
init();
_for(i, 1, 20)
_for(j, 1, i)
printf("%d %d %d\n", i, j, c[i][j]);
return 0;
}
字符串
kmp
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 1e6 + 10;
char a[N], b[N];
int Next[N], lena, lenb;
void get_next()
{
Next[0] = -1;
int i = 0, j = -1;
while(i < lenb)
{
if(j == -1 || b[i] == b[j])
{
i++; j++;
Next[i] = j;
}
else j = Next[j];
}
}
void kmp()
{
int i = 0, j = 0;
while(i < lena)
{
if(j == -1 || a[i] == b[j])
{
i++; j++;
if(j == lenb) printf("%d\n", i - j);
}
else j = Next[j];
}
}
int main()
{
scanf("%s%s", a, b);
lena = strlen(a);
lenb = strlen(b);
get_next();
kmp();
return 0;
}
哈希
求b在a中出现了多少次。kmp也可
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef unsigned long long ull;
const int N = 1e6 + 10;
const int base = 131;
ull Hash[N], p[N];
char a[N], b[N];
ull get(int l, int r)
{
return Hash[r] - Hash[l - 1] * p[r - l + 1];
}
int main()
{
scanf("%s%s", a + 1, b + 1);
int lena = strlen(a + 1);
p[0] = 1;
_for(i, 1, lena)
{
p[i] = p[i - 1] * base;
Hash[i] = Hash[i - 1] * base + a[i];
}
ull cur = 0;
int lenb = strlen(b + 1);
_for(i, 1, lenb) cur = cur * base + b[i];
int ans = 0;
_for(i, 1, lena)
{
int l = i, r = i + lenb - 1;
if(r > lena) break;
if(get(l, r) == cur) ans++;
}
printf("%d\n", ans);
return 0;
}
字典树
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 1e6 + 10;
int t[N][26], End[N], cnt, n, ans;
void add(string s)
{
int len = s.size(), p = 0;
rep(i, 0, len)
{
if(!t[p][s[i] - 'a']) t[p][s[i] - 'a'] = ++cnt;
p = t[p][s[i] - 'a'];
}
End[p]++;
if(End[p] > 1) ans = 1;
}
int main()
{
scanf("%d", &n);
_for(i, 1, n)
{
string s;
cin >> s;
add(s);
}
printf("%d\n", ans);
return 0;
}
图论
最短路
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll; //注意是否要开long long
const int N = 1e5 + 10;
struct node
{
int v; ll w;
bool operator < (const node& rhs) const
{
return w > rhs.w;
}
};
int n, m, s;
vector<node> g[N];
ll d[N];
void work()
{
priority_queue<node> q;
_for(i, 1, n) d[i] = 1e9;
d[s] = 0;
q.push({s, d[s]});
while(!q.empty())
{
node x = q.top(); q.pop();
int u = x.v;
if(d[u] != x.w) continue;
for(auto t: g[u])
{
int v = t.v, w = t.w;
if(d[v] > d[u] + w)
{
d[v] = d[u] + w;
q.push({v, d[v]});
}
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &s);
while(m--)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
g[u].push_back({v, w}); //读题注意是有向还是无向
}
work();
_for(i, 1, n) printf("%lld ", d[i]);
return 0;
}
LCA
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 5e5 + 10;
vector<int> g[N];
int d[N], up[N][21], n, m, s;
void dfs(int u, int fa)
{
d[u] = d[fa] + 1;
up[u][0] = fa;
_for(j, 1, 20) up[u][j] = up[up[u][j - 1]][j - 1];
for(int v: g[u])
{
if(v == fa) continue;
dfs(v, u);
}
}
int lca(int u, int v)
{
if(d[v] > d[u]) swap(u, v);
for(int j = 20; j >= 0; j--)
if(d[up[u][j]] >= d[v])
u = up[u][j];
if(u == v) return u;
for(int j = 20; j >= 0; j--)
if(up[u][j] != up[v][j])
u = up[u][j], v = up[v][j];
return up[u][0];
}
int main()
{
scanf("%d%d%d", &n, &m, &s);
_for(i, 1, n - 1)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(s, 0);
while(m--)
{
int u, v;
scanf("%d%d", &u, &v);
printf("%d\n", lca(u, v));
}
return 0;
}
nlogn最长不下降子序列
P1020 [NOIP1999 普及组] 导弹拦截
#include<bits/stdc++.h>
#define l(k) (k << 1)
#define r(k) (k << 1 | 1)
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 1e5 + 10;
const int H = 5e4;
int t[N << 2], a[N], dp[N], n;
void up(int k)
{
t[k] = max(t[l(k)], t[r(k)]);
}
void add(int k, int l, int r, int x, int p)
{
if(l == r)
{
t[k] = p;
return;
}
int m = l + r >> 1;
if(x <= m) add(l(k), l, m, x, p);
else add(r(k), m + 1, r, x, p);
up(k);
}
int ask(int k, int l, int r, int L, int R)
{
if(L > R) return 0;
if(L <= l && r <= R) return t[k];
int res = 0, m = l + r >> 1;
if(L <= m) res = max(res, ask(l(k), l, m, L, R));
if(R > m) res = max(res, ask(r(k), m + 1, r, L, R));
return res;
}
int main()
{
while(~scanf("%d", &a[++n]));
n--;
int ans = 0;
_for(i, 1, n)
{
dp[i] = ask(1, 1, H, a[i], H) + 1;
add(1, 1, H, a[i], dp[i]);
ans = max(ans, dp[i]);
}
printf("%d\n", ans);
ans = 0;
memset(t, 0, sizeof t);
_for(i, 1, n)
{
dp[i] = ask(1, 1, H, 1, a[i] - 1) + 1;
add(1, 1, H, a[i], dp[i]);
ans = max(ans, dp[i]);
}
printf("%d\n", ans);
return 0;
}