ACM模板 ——————by ALizen
0.模板
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<" ="<<x<<endl
using namespace std;
void scan(__int128 &x)//输入
{
x = 0;
int f = 1;
char ch;
if((ch = getchar()) == '-') f = -f;
else x = x*10 + ch-'0';
while((ch = getchar()) >= '0' && ch <= '9')
x = x*10 + ch-'0';
x *= f;
}
void print(__int128 x)
{
if(x < 0)
{
x = -x;
putchar('-');
}
if(x > 9) print(x/10);
putchar(x%10 + '0');
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}
1.数据结构
线段树
// 以加法线段树为模板
const int N = 1e5 + 10;
int w[N];
struct node {
int l, r;
ll val;
ll lazy;
}t[N << 2];
void pushdown(node& op, ll lazy) {
op.val += lazy * (op.r - op.l + 1);
op.lazy += lazy;
}
void pushdown(int x) {
if (!t[x].lazy) return;
pushdown(t[x << 1], t[x].lazy);
pushdown(t[x << 1 | 1], t[x].lazy);
t[x].lazy = 0;
}
void pushup(int x) {
t[x].val = t[x << 1].val + t[x << 1 | 1].val;
}
void build(int l, int r, int x = 1) {
t[x] = { l, r, w[l], 0 };
if (l == r) return;
int mid = l + r >> 1;
build(l, mid, x << 1), build(mid + 1, r, x << 1 | 1);
pushup(x);
}
void modify(int l, int r, int c, int x = 1) {
if (l <= t[x].l && r >= t[x].r) { pushdown(t[x], c); return; }
pushdown(x);
int mid = t[x].l + t[x].r >> 1;
if (l <= mid) modify(l, r, c, x << 1);
if (r > mid) modify(l, r, c, x << 1 | 1);
pushup(x);
}
ll query(int l, int r, int x = 1) {
if (l <= t[x].l && r >= t[x].r) return t[x].val;
pushdown(x);
int mid = t[x].l + t[x].r >> 1;
ll res = 0;
if (l <= mid) res += query(l, r, x << 1);
if (r > mid) res += query(l, r, x << 1 | 1);
return res;
}
线段树后续
1)多tag效应
struct node{
int l, r;
ll sum1, sum2, sum3;
ll add, mul, lazy;
}t[N << 2];
int n,m;
void pushup(int x){
node &p = t[x];
node &l = t[x << 1];
node &r = t[x << 1 | 1];
p.sum1 = (l.sum1 + r.sum1) % mod;
p.sum2 = (l.sum2 + r.sum2) % mod;
p.sum3 = (l.sum3 + r.sum3) % mod;
}
void pushdown(node &op, ll add, ll mul,ll lazy){
ll len = op.r - op.l + 1;
if (lazy) {
lazy %= mod;
op.sum1 = lazy * len % mod;
op.sum2 = lazy * lazy % mod * len % mod;
op.sum3 = lazy * lazy % mod * lazy % mod * len % mod;
op.add = 0, op.mul = 1; op.lazy = lazy;
}
if (mul != 1) {
op.sum1 = op.sum1 * mul % mod;
op.sum2 = op.sum2 * mul % mod * mul % mod;
op.sum3 = op.sum3 * mul % mod * mul % mod * mul % mod;
op.add = mul * op.add % mod;
op.mul = op.mul * mul % mod;
}
if (add) {
op.sum3 = (op.sum3 + len * add % mod * add % mod * add % mod + 3 * op.sum2 % mod * add % mod + 3 * op.sum1 % mod * add % mod * add % mod) % mod;
op.sum2 = (op.sum2 + 2 * add % mod * op.sum1 % mod + len * add % mod * add % mod) % mod;
op.sum1 = (op.sum1 + len * add % mod) % mod;
op.add = (op.add + add) % mod;
}
}
void pushdown(int x) {
node& p = t[x];
pushdown(t[x << 1], p.add, p.mul, p.lazy);
pushdown(t[x << 1 | 1], p.add, p.mul, p.lazy);
p.add = 0, p.mul = 1, p.lazy = 0;
}
void build(int l, int r, int x = 1){
t[x] = {l, r, 0, 0, 0, 0, 1, 0};
if(l == r)return ;
int mid = l + r >> 1;
build(l, mid, x << 1);
build(mid + 1, r, x << 1 | 1);
pushup(x);
}
void modify(int l,int r,int id, int c,int x = 1){
if(l <= t[x].l && r >= t[x].r){
if(id == 1) pushdown(t[x],c,1,0);
if(id == 2) pushdown(t[x],0,c,0);
if(id == 3) pushdown(t[x],0,1,c);
return ;
}
pushdown(x);
int mid = t[x].l + t[x].r >> 1;
if(l <= mid) modify(l,r,id,c,x << 1);
if(r > mid) modify(l,r,id,c,x << 1 | 1);
pushup(x);
}
int query(int l,int r,int id,int x = 1){
if(l <=t[x].l && r >= t[x].r){
if(id == 1) return t[x].sum1;
if(id == 2) return t[x].sum2;
if(id == 3) return t[x].sum3;
}
pushdown(x);
int mid = t[x].l + t[x].r >> 1;
int res = 0;
if(l <= mid) res = (res + query(l,r,id,x<< 1));
if(r > mid) res = (res + query(l,r,id,x<< 1 | 1));
return res % mod;
}
2)合并操作
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef long long ll;
inline void rd();
inline void ot();
inline void debug();
const int INF = 0x3f3f3f3f;
const int N = 2e5+7;
struct node{
int l,r;
int sum[3];
}t[N << 2];
char s[N];
node operator + (const node& A,const node& B){
node res;
res.l = A.l;
res.r = B.r;
res.sum[0] = A.sum[0]+B.sum[A.sum[0]%3];
res.sum[1] = A.sum[1]+B.sum[(1+A.sum[1])%3];
res.sum[2] = A.sum[2]+B.sum[(2+A.sum[2])%3];
return res;
}
void pushup(int x){
t[x].sum[0] = t[x << 1].sum[0] + t[x << 1|1].sum[t[x << 1].sum[0] % 3];
t[x].sum[1] = t[x << 1].sum[1] + t[x << 1|1].sum[(1+t[x << 1].sum[1]) % 3];
t[x].sum[2] = t[x << 1].sum[2] + t[x << 1|1].sum[(2+t[x << 1].sum[2] )% 3];
}
void build(int l,int r,int x = 1){
t[x].l = l;
t[x].r = r;
if(l == r){
if(s[l] == 'W') t[x].sum[0] = t[x].sum[1] = t[x].sum[2] = 1;
else if(s[l] == 'D') t[x].sum[0] = t[x].sum[1] = t[x].sum[2] = 0;
else t[x].sum[0] =0, t[x].sum[1] = t[x].sum[2] = -1;
return ;
}
int mid = l + r >> 1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
pushup(x);
}
node query(int l,int r,int x = 1){
if(l <= t[x].l && t[x].r <= r) return t[x];
int mid = t[x].l + t[x].r >> 1;
if(l > mid) return query(l,r,x << 1|1) ;
else if(r <= mid) return query(l,r, x<< 1);
else return query(l,mid, x << 1) + query(mid+1,r,x<< 1|1);
}
void HHU_zyh(){
int n,t;
cin >> n >> t;
cin >> s+1;
build(1,n);
while(t--){
int l,r,s;
cin >> l >> r >> s;
node res = query(l,r);
cout << s + res.sum[s%3] << endl;
}
}
3)权值线段树
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
int n,k;
const int N = 1e5+7;
const int M = 1e6+7;
struct node{
int l,r;
int v;
ll sum;
}t[M<<2];
int w[N];
void build(int l,int r,int x = 1){
t[x].l = l,t[x].r = r;
if(l == r) return ;
int mid = l + r >> 1;
build(l, mid, x << 1), build(mid + 1, r, x << 1 | 1);
}
void pushup(int x){
t[x].sum = t[x<<1].sum + t[x<<1|1].sum;
t[x].v = t[x<<1].v + t[x<<1|1].v;
}
void modify(int pos,int v,int x = 1){
if(t[x].l == t[x].r) {
t[x].v += v;
t[x].sum += pos * v;
return;
}
int mid = (t[x].l + t[x].r) >> 1;
if(pos <= mid) modify(pos,v,x<<1);
else modify(pos,v,x<<1|1);
pushup(x);
}
int query_kth(int k,int x = 1){
if(t[x].l == t[x].r) return t[x].l;
if(k <= t[x<<1].v) return query_kth(k,x<<1);
else return query_kth(k-t[x<<1].v,x<<1|1);
}
int get_num(int l,int r,int x = 1){
if(l <= t[x].l && t[x].r <= r) return t[x].v;
int ans = 0;
int mid = (t[x].l + t[x].r) >> 1;
if(l <= mid) ans += get_num(l,r,x<<1);
if(r > mid )ans += get_num(l,r,x<<1|1);
return ans;
}
ll get_sum(int l,int r,int x = 1){
if(l <= t[x].l && t[x].r <= r) return t[x].sum;
ll ans = 0;
int mid = (t[x].l + t[x].r) >> 1;
if(l <= mid) ans += get_sum(l,r,x<<1);
if(r > mid) ans += get_sum(l,r,x<<1|1);
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> k;
int mx = -1;
for(int i = 1;i<=n;i++) {
cin >> w[i];
mx = max(w[i],mx);
}
build(0,mx);
//pf(mx);
for(int i = 1;i<k;i++) modify(w[i],1);
ll ans = 1e15;
for(int i = k;i<=n;i++){
modify(w[i],1);
int mid = query_kth(k/2+1);
//pf(mid);
ll pre_num = get_num(0,mid);
//pf(pre_num);
ll aft_num = get_num(mid,mx);
//pf(aft_num);
ll res = mid * pre_num - get_sum(0,mid) + get_sum(mid,mx) - mid * aft_num;
ans = min(ans,res);
modify(w[i-k+1],-1);
}
cout << ans;
return 0;
}
4)主席树
int lch[N<<5],rch[N<<5];
int a[N],b[N];
int n,m;
int root[N<<5],tot;
int sum[N<<5];
int num;
void modify(int &rt,int old,int l,int r,int x){
rt = ++ tot;
lch[rt] = lch[old];
rch[rt] = rch[old];
sum[rt] = sum[old] + 1;
if(l == r) return;
int mid = l + r >> 1;
if(x <= mid) modify(lch[rt],lch[rt],l,mid,x);
else modify(rch[rt],rch[rt],mid+1,r,x);
}
int query(int u,int v,int l,int r,int k){
if(l == r) return l;
int x = sum[lch[v]] - sum[lch[u]];
int mid = l + r >> 1;
if(x >= k) return query(lch[u],lch[v],l,mid,k);
else return query(rch[u],rch[v],mid+1,r,k-x);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> a[i];
b[i] = a[i];
}
sort(b+1,b+1+n);
num = unique(b+1,b+1+n) - (b+1);
for(int i = 1; i <= n; i++){
int pos = lower_bound(b+1,b+1+num,a[i]) - b;
modify(root[i],root[i-1],1,num,pos);
}
while(m--){
int l,r,k;
cin >> l >> r >> k;
cout << b[query(root[l-1],root[r],1,num,k)] <<'\n';
}
return 0;
}
左偏树
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
const int N = 1e6+7;
int l[N],r[N],val[N],p[N];
int dist[N];
int book[N];
int n,m;
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int merge(int x,int y){
if(!x || !y) return x+y;
if(val[x] > val[y]) swap(x,y);
r[x] = merge(r[x],y);
p[r[x]] = x;
if(dist[r[x]] > dist[l[x]]) swap(l[x],r[x]);
dist[x] = dist[r[x]] + 1;
return x;
}
void solve(){
char op;
cin >> op;
if(op == 'M') {
int u,v;
cin >> u >> v;
if(book[u] || book[v]) return;
int a = find(u);
int b = find(v);
if(a == b) return;
int anc = merge(a,b);
p[a] = p[b] = anc;
}
else{
int k;
cin >> k;
if(book[k]){
cout <<"0\n";
return;
}
int anc = find(k);
book[anc] = 1;
cout << val[anc] <<'\n';
int fa = merge(l[anc],r[anc]);
p[anc] = fa;
p[fa] = fa;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for(int i = 1; i<=n; i++){
cin >> val[i];
p[i] = i;
}
dist[0] = -1;
cin >> m;
while(m--) solve();
return 0;
}
并查集
int n,m;
const int N=1e6+7;
int p[N],s[N];
void init(){
for(int i=1;i<=n;i++){
p[i]=i;
cin>>s[i];
}
}
int find(int x){
if(p[x]!=x){
s[x]=max(s[x],s[p[x]]);
p[x]=find(p[x]);
}
return p[x];
}
int main(){
cin>>n>>m;
init();
while(m--){
int a,b;
cin>>a>>b;
int u=find(a),v=find(b);
if(u!=v){
p[u]=v;
s[v]=max(s[u],s[v]);
}
}
LL sum=0;
for(int i=1;i<=n;i++){
sum+=s[find(i)];
}
cout<<sum<<endl;
return 0;
}
树状数组
1)区间修改,单点查询
void add(int p, int x){ //这个函数用来在树状数组中直接修改
while(p <= n) sum[p] += x, p += p & -p;
}
void range_add(int l, int r, int x){ //给区间[l, r]加上x
add(l, x), add(r + 1, -x);
}
int ask(int p){ //单点查询
int res = 0;
while(p) res += sum[p], p -= p & -p;
return res;
}
range_add(i,i,x)
2)单点修改,区间查询
int lowbit(int x){
return x&-x;
}
void add(int p,ll c){
while(p <= n){
a[p] += c;
p += lowbit(p);
}
}
void range_add(int l,int r,ll c){
add(l,c),add(r+1,-c);
}
ll get_sum(int p){
ll res = 0;
while(p){
res += a[p];
p -= lowbit(p);
}
return res;
}
add(i,x)
3)区间修改,区间查询
int lowbit(int x){
return x&-x;
}
void add(ll p, ll x){
for(int i = p; i <= n; i += i & -i)
sum1[i] += x, sum2[i] += x * p;
}
void range_add(ll l, ll r, ll x){
add(l, x), add(r + 1, -x);
}
ll ask(ll p){
ll res = 0;
for(int i = p; i; i -= i & -i)
res += (p + 1) * sum1[i] - sum2[i];
return res;
}
ll range_ask(ll l, ll r){
return ask(r) - ask(l - 1);
}
range_add(i,i,x)
4)二维单点修改,区间查询
void add(int x, int y, ll z){ //将点(x, y)加上z
int memo_y = y;
while(x <= n){
y = memo_y;
while(y <= m)
tree[x][y] += z, y += y & -y;
x += x & -x;
}
}
ll ask(int x, int y){//求左上角为(1,1)右下角为(x,y) 的矩阵和
ll res = 0, memo_y = y;
while(x){
y = memo_y;
while(y)
res += tree[x][y], y -= y & -y;
x -= x & -x;
}
return res;
}
5)二维区间修改,单点查询
void add(int x, int y, ll z){
int memo_y = y;
while(x <= n){
y = memo_y;
while(y <= m)
tree[x][y] += z, y += y & -y;
x += x & -x;
}
}
void range_add(int xa, int ya, int xb, int yb, ll z){
add(xa, ya, z);
add(xa, yb + 1, -z);
add(xb + 1, ya, -z);
add(xb + 1, yb + 1, z);
}
ll ask(int x, int y){
ll res = 0, memo_y = y;
while(x){
y = memo_y;
while(y)
res += tree[x][y], y -= y & -y;
x -= x & -x;
}
return res;
}
6)二维区间修改,区间查询
ll t1[N][N], t2[N][N], t3[N][N], t4[N][N];
void add(ll x, ll y, ll z){
for(int X = x; X <= n; X += X & -X)
for(int Y = y; Y <= m; Y += Y & -Y){
t1[X][Y] += z;
t2[X][Y] += z * x;
t3[X][Y] += z * y;
t4[X][Y] += z * x * y;
}
}
void range_add(ll xa, ll ya, ll xb, ll yb, ll z){ //(xa, ya) 到 (xb, yb) 的矩形
add(xa, ya, z);
add(xa, yb + 1, -z);
add(xb + 1, ya, -z);
add(xb + 1, yb + 1, z);
}
ll ask(ll x, ll y){
ll res = 0;
for(int i = x; i; i -= i & -i)
for(int j = y; j; j -= j & -j)
res += (x + 1) * (y + 1) * t1[i][j]
- (y + 1) * t2[i][j]
- (x + 1) * t3[i][j]
+ t4[i][j];
return res;
}
ll range_ask(ll xa, ll ya, ll xb, ll yb){
return ask(xb, yb) - ask(xb, ya - 1) - ask(xa - 1, yb) + ask(xa - 1, ya - 1);
}
分块
//动态求数组中小于c*c的元素
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
const int N = 500500;
vector<int> v[3000];
int block,sum;
int n;
int a[N];
int pos[N],tag[N];
void init(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
block = sqrt(n);
sum = n / block + (n%block==0?0:1);
for(int i = 1;i<=n;i++){
pos[i] = (i-1)/block+1;
v[pos[i]].push_back(a[i]);
}
for(int i = 1;i<=sum;i++) sort(v[i].begin(),v[i].end());
}
void update(int x){
v[pos[x]].clear();
for(int i = (pos[x]-1)*block+1;i<=min(pos[x]*block,n);i++) v[pos[x]].push_back(a[i]);
sort(v[pos[x]].begin(),v[pos[x]].end());
}
void modify(int l,int r,int x){
for(int i = l;i<=min(r,pos[l]*block);i++) a[i] += x;
update(l);
if(pos[l] != pos[r]) {
for(int i = (pos[r]-1)*block+1;i<=r;i++) a[i] +=x;
update(r);
}
for(int i = pos[l]+1;i<=pos[r]-1;i++) tag[i]+=x;
}
int query(int l,int r,int k){
int res = 0;
for(int i = l;i<=min(r,pos[l]*block);i++) if(a[i]+tag[pos[i]]<k) res++;
if(pos[l] != pos[r]) for(int i = (pos[r]-1)*block+1;i<=r;i++) if(a[i]+tag[pos[i]]<k) res++;
for(int i = pos[l]+1;i<=pos[r]-1;i++){
int tmp = k - tag[i];
res += lower_bound(v[i].begin(),v[i].end(),tmp) - v[i].begin();
}
return res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
init();
for(int _=1;_<=n;_++){
int op,l,r,c;
cin >> op >> l >> r >> c;
if(!op) modify(l,r,c);
else cout << query(l,r,c*c)<<'\n';
}
return 0;
}
2.图论
求最短路
1)Dijkstra
const int N = 1e6 + 7;
const int INF = 0x3f3f3f3f;
int n, m;
vector<PII> edge[N];
int dist[N],book[N];
int dijkstra(){
dist[1]=0;
priority_queue<PII, vector<PII>,greater<PII>> pq;
pq.push({0,1});
while(pq.size()){
PII tep = pq.top();
pq.pop();
int dis = tep.first, pos = tep.second;
if(book[pos]) continue;
book[pos] = 1;
for(auto pr : edge[pos]){
int w = pr.first;
int v = pr.second;
if(dist[v] > dis + w){
dist[v] > dis + w;
pq.push({dist[v],v});
}
}
}
if(dist[n] == INF) return -1;
return dist[n];
}
int main(){
scanf("%d%d",&n,&m);
MEM(dist,INF);
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
edge[a].push_back({c,b});
}
int ans = dijkstra();
pf(ans);
return 0;
}
2)Spfa
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n,m;
vector<PII> edge[N];
int dist[N];
int book[N];
int spfa(){
queue<int> q;
for(int i=1; i<=n; i++){
q.push(i);
book[i] = 1;
}
while(q.size()){
int t = q.front();
q.pop();
book[t] = 0;
for(auto j : edge[t]){
int pos;
int distance;
pos = j.first;
distance = j.second;
if(dist[pos] > dist[t] + distance){
dist[pos] = dist[t] + distance;
cnt[pos] = cnt[t] + 1;
if(cnt[pos] >= n) return 1;
if(!book[pos]){
q.push(pos);
book[pos] = 1;
}
}
}
}
return 0;
}
void MorningStar(){
scanf("%d %d",&n,&m);
while(m--){
int a,b,c;
scanf("%d %d %d",&a, &b, &c);
edge[a].push_back({b,c});
}
int ans;
ans = spfa();
if(ans) printf("Yes");
else printf("No");
}
3)Bellmen-Ford
int n, m, k;
int dist[N], backup[N];
vector<PII> edge[N];
int bellman_ford(){
memset(dist, INF, sizeof dist);
dist[1] = 0;
for(int kase = 0; kase < k; kase ++) {
memcpy(backup, dist, sizeof dist);
for(int i = 1; i <= n; i++){
for(auto j : edge[i]){
int st,ed,distance;
st = i;
ed = j.first;
distance = j.second;
dist[ed] = min(backup[st] + distance, dist[ed]);
}
}
}
if(dist[n] >= INF / 2) return INF;
return dist[n];
}
void Smokers(){
scanf("%d %d %d",&n, &m, &k);
while(m--){
int a,b,w;
scanf("%d%d%d",&a, &b, &w);
edge[a].push_back({b,w});
}
int ans = bellman_ford();
if(ans== INF) printf("impossible");
else printf("%d",ans);
}
4)Floyd
int n, m, q;
int d[N][N];
void floyd(){
for(int k = 1; k <= n; k ++ ){
for(int i = 1; i <=n ;i++){
for(int j = 1;j <=n; j++){
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
}
void Smokers(){
scanf("%d %d %d",&n,&m,&q);
for(int i=1; i<=n; i++){
for(int j=1; j <= n; j++){
if(i == j) d[i][j] = 0;
else d[i][j] = INF;
}
}
while(m--){
int a, b, c;
scanf("%d %d %d",&a, &b, &c);
d[a][b] = min(d[a][b], c);
}
floyd();
while(q -- ){
int a, b;
scanf("%d %d",&a,&b);
if(d[a][b] == INF) printf("impossible");
else printf("%d",d[a][b]);
}
}
欧拉回路
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
const int N = 100100, M = 400100;
int h[N],e[M],ne[M],idx;
int ans[N<<1],cnt;
bool used[M];
int din[N],dout[N];
int n,m,ver;
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int u){
for(int &i = h[u]; ~i; ){
if(used[i]){
i = ne[i]; continue;
}
used[i] = 1;
if(ver == 1) used[i^1] = 1;
int t;
if(ver == 1){
t = i / 2 + 1;
if(i & 1) t = -t;
}
else t = i + 1;
int j = e[i];
i = ne[i];
dfs(j);
ans[++cnt] = t;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> ver >> n >> m;
memset(h,-1,sizeof h);
for(int i = 1; i <= m; i ++){
int a,b;
cin >> a >> b;
add(a,b);
if(ver == 1) add(b,a);
din[b]++;dout[a]++;
}
if(ver == 1){
for(int i = 1; i <= n; i ++){
if(din[i] + dout[i] & 1){
puts("NO"); return 0;
}
}
}
else{
for(int i = 1; i <= n; i ++){
if(din[i] != dout[i]){
puts("NO"); return 0;
}
}
}
for(int i = 1; i <= n; i ++){
if(~h[i]) {
dfs(i);break;
}
}
if(cnt < m){
puts("NO");return 0;
}
cout <<"YES\n";
for(int i = cnt; i >= 1; i --) cout << ans[i] <<" ";
return 0;
}
二分图
匈牙利算法
vector<int> edge[N];
int book[N];//右边否有被匹配
int match[N];//右边和左边哪个点联系
bool find(int x){
for(auto k : edge[x]){
if(!book[k]){
book[k] = 1;
if(match[k] == 0 || find(match[k])){
match[k] = x;
return true;
}
}
}
return false;
}
void MorningStar(){
int n1,n2,m;
cin >> n1 >> n2 >> m;
while(m--){
int u,v;
cin >> u >> v;
edge[u].push_back(v);
}
MEM(book,0);
MEM(match,0);
int res = 0;
for(int i = 1;i <= n1; i ++){
MEM(book,0);
if(find(i)) res++;
}
cout << res << '\n';
}
图的最小割
int n,m;
ll res;
int v[N];
int book[N];
ll dist[N];
ll g[N][N];
void Mincut(int n){
for(int i = 0;i<n;i++) v[i] = i;
while(n>1){
int maxj = 1;
int pre = 0;
for(int i=1; i<n; ++i)
{
dist[v[i]]=g[v[0]][v[i]];
if(dist[v[i]]>dist[v[maxj]]) maxj=i;
}
MEM(book,0);
book[v[0]] = 1;
for(int i =1;i<n;i++){
if(i == n-1){
res = min(res,dist[v[maxj]]);
for(int k = 0;k<n;k++){
g[v[k]][v[pre]] = (g[v[pre]][v[k]] += g[v[maxj]][v[k]]);
}
v[maxj] = v[--n];
}
book[v[maxj]] = 1;
pre = maxj;
maxj = -1;
for(int j =1 ;j<n;j++){
if(!book[v[j]]){
dist[v[j]] += g[v[pre]][v[j]];
if(maxj == -1 || (dist[v[j]] > dist[v[maxj]]))
maxj = j;
}
}
}
}
return ;
}
void MorningStar(){
cin >> n >> m;
ll sum = 0;
while(m--){
int u,v;
ll w;
cin >> u >> v >> w;
//1-n 用这个
u--,v--;
g[u][v] = w;
g[v][u] = w;
sum +=w;
}
res = 1e18+7;
Mincut(n);
sum-=res;
cout << 2*sum <<endl;
}
int main(){
IOS;
rd();
MorningStar();
ot();
return 0;
}
有向图强连通分量
vector<int> edge[N];
int dfn[N],low[N];
int id[N],siz[N];
int tot,scc_cnt;
int out[N];
stack<int> st;
bool book[N];
void tarjan(int u){
dfn[u] = low[u] = ++tot;
st.push(u);
book[u] = 1;
for(auto k : edge[u]){
if(!dfn[k]){
tarjan(k);
low[u] = min(low[u],low[k]);
}
else if(book[k]) low[u] = min(low[u],dfn[k]);
}
if(dfn[u] == low[u]){
++scc_cnt;
int y;
do{
y = st.top();
st.pop();
book[y] = 0;
id[y] = scc_cnt;
siz[scc_cnt]++;
}while(y != u);
}
}
无向图双连通分量
1)点双连通分量
const int N = 1e4+7;
int n,m;
vector<int> edge[N];
int dfn[N], low[N], timestamp;
int stk[N], top;
int dcc_cnt;
vector<int> dcc[N];
bool is_cut[N];
int root;
int idx;
void add(int a,int b){
edge[a].push_back(b);
}
void tarjan(int u){
low[u] = dfn[u] = ++timestamp;
stk[++top] = u;
if(u == root && !edge[u].size()){
dcc_cnt++;
dcc[dcc_cnt].push_back(u);
return;
}
int cnt = 0;
for(auto j : edge[u]){
if(!dfn[j]){
tarjan(j);
low[u] = min(low[u],low[j]);
if(dfn[u] <= low[j]){
cnt++;
if(u != root || cnt > 1) is_cut[u] = true;
++dcc_cnt;
int y;
do{
y = stk[top--];
dcc[dcc_cnt].push_back(y);
}while(y != j);
dcc[dcc_cnt].push_back(u);
}
}
else low[u] = min(low[u],dfn[j]);
}
}
void solve(int id){
cout <<"Case "<<id<<": ";
for(int i = 1; i <= dcc_cnt; i ++) dcc[i].clear();
for(int i = 1; i <= n; i ++) edge[i].clear();
top = 0;
dcc_cnt = 0;
timestamp = 0;
n = 0;
memset(dfn,0,sizeof dfn);
memset(is_cut,0,sizeof is_cut);
while(m --){
int a,b;
cin >> a >> b;
n = max({n,a,b});
add(a,b),add(b,a);
}
for(root = 1; root <= n; root ++){
if(!dfn[root]) tarjan(root);
}
int res = 0;
ull num = 1;
//pf(dcc_cnt);
for(int i = 1; i <= dcc_cnt; i ++){
int cnt = 0;
for(auto k : dcc[i]){
if(is_cut[k]) cnt++;
}
if(cnt == 0){
if(dcc[i].size() > 1) res += 2,num *=dcc[i].size()*(dcc[i].size()-1)/2;
else res ++;
}
else if(cnt == 1){
res++; num *= dcc[i].size()-1;
}
}
cout << res <<" "<<num <<'\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
while(cin >> m,m) solve(++idx);
return 0;
}
2)边双连通分量
//这里用了邻接表来存图
const int N = 5010, M = 20010;
int n, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
int id[N], dcc_cnt;
bool is_bridge[M];
int d[N];
void add(int a, int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
void tarjan(int u, int from)
{
dfn[u] = low[u] = ++ timestamp;
stk[ ++ top] = u;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (!dfn[j])
{
tarjan(j, i);
low[u] = min(low[u], low[j]);
if (dfn[u] < low[j])
is_bridge[i] = is_bridge[i ^ 1] = true;
}
else if (i != (from ^ 1))
low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u])
{
++ dcc_cnt;
int y;
do {
y = stk[top -- ];
id[y] = dcc_cnt;
} while (y != u);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
memset(h,-1,sizeof h);
cin >> n >> m;
while(m --) {
int a,b;
cin >> a >> b;
add(a,b),add(b,a);
}
tarjan(1,-1);
for(int i = 0; i < idx; i++){
if(is_bridge[i]) d[id[e[i]]]++;
}
int cnt = 0;
for(int i = 1; i <= dcc_cnt; i ++){
if(d[i] == 1) cnt++;
}
cout << (cnt+1)/2;
return 0;
}
最小生成树
const int N=2e5+7;
int p[N];
struct Edge{
int a,b,w;
}edge[N];
bool cmp(Edge a,Edge b){
return a.w<b.w;
}
int find(int x){
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
edge[i].a=a;
edge[i].b=b;
edge[i].w=c;
}
fer(i,1,n)p[i]=i;
sort(edge+1,edge+1+m,cmp);
int res=0,cnt=0;
for(int i=1;i<=m;i++){
int a=edge[i].a,b=edge[i].b,w=edge[i].w;
a=find(a),b=find(b);
if(a!=b){
p[a]=b;
res+=w;
cnt++;
}
}
if(cnt!=n-1)puts("impossible");
else pf(res);
return 0;
}
次小生成树
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
const int N = 1e5+7;
const int INF = 0x3f3f3f3f;
int n,m;
vector<pair<int,int>> edge[N];
struct node{
int a,b,c;
bool used;
bool operator < (const node a) const{
return c < a.c;
}
}e[N];
int p[N];
int depth[N], fa[N][17], d1[N][17], d2[N][17];
void add(int a,int b,int c){
edge[a].push_back({c,b});
}
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
ll mst(){
for(int i = 1; i <= n; i ++) p[i] = i;
sort(e+1,e+1+m);
ll res = 0;
for(int i = 1; i <= m; i++){
int a = e[i].a;
int b = e[i].b;
int c = e[i].c;
a = find(a);
b = find(b);
if(a != b){
p[a] = b;
res += c;
e[i].used = 1;
}
}
return res;
}
void build(){
for(int i = 1; i <= m; i ++){
if(e[i].used){
int a = e[i].a;
int b = e[i].b;
int c = e[i].c;
add(a,b,c);
add(b,a,c);
}
}
}
void bfs(){
memset(depth, 0x3f, sizeof depth);
depth[0] = 0, depth[1] = 1;
queue<int> q;
q.push(1);
while (!q.empty()){
int pos = q.front();
q.pop();
for (auto pr : edge[pos]){
int w = pr.first;
int v = pr.second;
if (depth[v] > depth[pos] + 1){
depth[v] = depth[pos] + 1;
q.push(v);
fa[v][0] = pos;
d1[v][0] = w, d2[v][0] = -INF;
for (int k = 1; k <= 16; k ++ ){
int anc = fa[v][k - 1];
fa[v][k] = fa[anc][k - 1];
int distance[4] = {d1[v][k - 1], d2[v][k - 1], d1[anc][k - 1], d2[anc][k - 1]};
d1[v][k] = d2[v][k] = -INF;
for (int u = 0; u < 4; u ++ ){
int d = distance[u];
if (d > d1[v][k]) d2[v][k] = d1[v][k], d1[v][k] = d;
else if (d != d1[v][k] && d > d2[v][k]) d2[v][k] = d;
}
}
}
}
}
}
int lca(int a,int b,int w){
static int distance[N * 2];
int cnt = 0;
if (depth[a] < depth[b]) swap(a, b);
for (int k = 16; k >= 0; k -- ){
if (depth[fa[a][k]] >= depth[b]){
distance[++cnt] = d1[a][k];
distance[++cnt] = d2[a][k];
a = fa[a][k];
}
}
if (a != b){
for (int k = 16; k >= 0; k -- ){
if (fa[a][k] != fa[b][k]){
distance[++cnt] = d1[a][k];
distance[++cnt] = d2[a][k];
distance[++cnt] = d1[b][k];
distance[++cnt] = d2[b][k];
a = fa[a][k], b = fa[b][k];
}
}
distance[++cnt] = d1[a][0];
distance[++cnt] = d1[b][0];
}
int dist1 = -INF, dist2 = -INF;
for (int i = 1; i <= cnt; i ++ ){
int d = distance[i];
if (d > dist1) dist2 = dist1, dist1 = d;
else if (d != dist1 && d > dist2) dist2 = d;
}
if (w > dist1) return w - dist1;
if (w > dist2) return w - dist2;
return INF;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for(int i = 1; i <= m; i ++){
int a,b,c;
cin >> a >> b >> c;
e[i] = {a,b,c};
}
ll sum = mst();
build();
bfs();
ll res = 1e18;
for(int i = 1; i <= m; i ++){
if(!e[i].used){
int a = e[i].a;
int b = e[i].b;
int c = e[i].c;
res = min(res,sum + lca(a,b,c));
}
}
cout << res;
return 0;
}
LCA
倍增
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<"="<<x<<endl
using namespace std;
const int N = 4e4+7;
int depth[N];
int fa[N][20];
int n,m;
vector<int> edge[N];
int root;
void add(int a,int b){
edge[a].push_back(b);
}
void bfs(){
memset(depth,0x3f,sizeof depth);
queue<int> q;
q.push(root);
depth[0] = 0;
depth[root] = 1;
while(!q.empty()){
int pos = q.front();
q.pop();
for(auto k : edge[pos]){
if(depth[k] > depth[pos] + 1){
depth[k] = depth[pos] + 1;
q.push(k);
fa[k][0] = pos;
for(int j = 1;j<=15;j++){
fa[k][j] = fa[fa[k][j-1]][j-1];
}
}
}
}
}
void dfs(int x,int u){
for(auto k : edge[x]){
if(k == u) continue;
depth[k] = depth[x] + 1;
fa[k][0] = x;
for(int j = 1; j<= 15; j++){
fa[k][j] = fa[fa[k][j-1]][j-1];
}
dfs(k,x);
}
}
int lca(int a,int b){
if(depth[a] < depth[b]) swap(a,b);
for(int k = 15; k >= 0; k--){
if(depth[fa[a][k]] >= depth[b]){
a = fa[a][k];
}
}
if(a == b) return a;
for(int k = 15;k >= 0; k--){
if(fa[a][k]!=fa[b][k]){
a = fa[a][k];
b = fa[b][k];
}
}
return fa[a][0];
}
Tarjan
typedef pair<int,int> PII;
const int N = 2e4+7;
int n,m;
vector<PII> edge[N];
int st[N];
int depth[N];
int p[N];
int ans[N];
struct node{
int v;
int id;
};
vector<node> q[N];
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void dfs(int x,int u){
for(auto pr : edge[x]){
int w = pr.first;
int v = pr.second;
if(v == u) continue;
depth[v] = depth[x] + w;
dfs(v,x);
}
}
void tarjan(int x){
st[x] = 1;
for(auto pr : edge[x]){
int v = pr.second;
if(st[v] == 0){
tarjan(v);
p[v] = x;
}
}
for(auto pr : q[x]){
int id = pr.id;
int v = pr.v;
if(st[v] == 2){
int fa = find(v);
ans[id] = depth[x] + depth[v] - 2*depth[fa];
}
}
st[x] = 2;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for(int i = 1; i < n; i++){
int x,y,k;
cin >> x >> y >> k;
edge[x].push_back({k,y});
edge[y].push_back({k,x});
}
for(int i = 1; i <= m; i++){
int x,y;
cin >> x >> y;
if(x != y){
q[x].push_back({y,i});
q[y].push_back({x,i});
}
}
for(int i = 1; i <= n; i++) p[i] = i;
dfs(1,-1);
tarjan(1);
for(int i = 1; i <= m; i++) cout << ans[i] <<'\n';
return 0;
}
3.数论
快速幂
ll ksm(ll a,ll b){
ll res=1;
while(b){
if(b&1)res=res*a%mod;
b>>=1;
a = a * a % mod;
}
return res;
}
NTT
#include <bits/stdc++.h>
#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<" ="<<x<<endl
using namespace std;
const ll mod = 998244353;
const int N = 4e6+10;
ll n,len;
ll jc[N],jc_inv[N];
ll a[N<<1],b[N<<1];
const ll G = 3,P = mod;
ll R[N<<1];
ll ksm(ll a, ll b){
ll res = 1;
while(b){
if(b&1) res = res * a %mod;
a = a*a %mod;
b >>= 1;
}
return res;
}
void NTT(ll *a, ll f)
{
for (ll i = 0; i < n; i++)
if (i < R[i])
swap(a[i], a[R[i]]);
for (ll i = 1; i < n; i <<= 1)
{
ll gn = ksm(G, (P - 1) / (i << 1));
for (ll j = 0; j < n; j += (i << 1))
{
ll g = 1;
for (ll k = 0; k < i; k++, g = 1ll * g %P* gn % P)
{
ll x = a[j + k], y = 1ll * g%P * a[j + k + i] % P;
a[j + k] = (x + y) % P;
a[j + k + i] = (x - y + P) % P;
}
}
}
if (f == 1)
return;
int nv = ksm(n, P - 2);
reverse(a + 1, a + n);
for (int i = 0; i < n; i++)
a[i] = 1ll * a[i] * nv % P;
}
void init(){
jc[0] = 1;
jc_inv[0] = 1;
for(ll i = 1;i<=n;i++){
jc[i] = jc[i-1]*i%mod;
jc_inv[i] = ksm(jc[i],mod-2);
}
for(int i = 0; i < n;i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) ? (n>>1): 0);
}
ll C(ll x, ll y){
return jc[x] * jc_inv[y] % mod * jc_inv[x - y] % mod;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >>len;
n = 1;
while(n<len) n<<=1;
n <<= 1;
init();
for(ll i = 0; i <= len/3;i++){
a[i] = jc[i] * C(len-2*i,i) %mod * ksm(26,len-3*i) %mod;
}
for(ll i = 0; i <= len; i++){
b[i] = jc_inv[len-i] * ((len-i)%2==1?-1:1);
}
NTT(a,1);
NTT(b,1);
for(ll i = 0; i<n;i++) a[i] = a[i] * b[i] % mod;
NTT(a,-1);
for(int i = 0;i <=len; i++){
cout << (a[len+i] * jc_inv[i] % mod + mod )%mod<<' ';
}
return 0;
}
//second
#include <bits/stdc++.h>
#define int long long
#define poly vector<int>
#define len(x) ((int)x.size())
using namespace std;
const int N = 2e4 + 5, M = 35, g = 3, ginv = 332748118, mod = 998244353;
int n, m, rev[N], lim, liminv, cnt[35], fact[N], infact[N], res;
string str;
poly ans, tmp;
int qmi(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void NTT(poly &f, int op) {
for (int i = 0; i < lim; i ++) {
if (i < rev[i]) swap(f[i], f[rev[i]]);
}
for (int mid = 1; mid < lim; mid <<= 1) {
int gn = qmi(op == 1 ? g : ginv, (mod - 1) / (mid << 1));
for (int i = 0; i < lim; i += mid * 2) {
for (int j = 0, g0 = 1; j < mid; j ++, g0 = g0 * gn % mod) {
int x = f[i + j], y = g0 * f[i + j + mid] % mod;
f[i + j] = (x + y) % mod, f[i + j + mid] = (x - y + mod) % mod;
}
}
}
if (op == -1) {
for (int i = 0; i < lim; i ++) f[i] = f[i] * liminv % mod;
}
}
poly operator * (poly f, poly g) {
int n = len(f) + len(g) - 1;
for (lim = 1; lim < n; lim <<= 1); liminv = qmi(lim, mod - 2);
for(int i = 0; i < lim; i ++) rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? lim >> 1 : 0);
f.resize(lim), g.resize(lim);
NTT(f, 1), NTT(g, 1);
for (int i = 0; i < lim; i ++) f[i] = f[i] * g[i] % mod;
NTT(f, -1), f.resize(n);
return f;
}
signed main() {
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++) {
fact[i] = fact[i - 1] * i % mod;
infact[i] = infact[i - 1] * qmi(i, mod - 2) % mod;
}
cin >> str;
for (int i = 0; i < str.size(); i ++) {
cnt[str[i] - 'a'+1] ++;
}
ans.resize(cnt[1] + 1);
for (int i = 0; i <= cnt[1]; i ++) {
ans[i] = infact[i];
}
for (int i = 2; i <= 26; i ++) {
tmp.resize(cnt[i] + 1);
for (int j = 0; j <= cnt[i]; j ++) {
tmp[j] = infact[j];
}
ans = ans * tmp;
}
for (int i = 1; i < len(ans); i ++) {
res = (res + fact[i] * ans[i] % mod) % mod;
}
cout << res ;
}
中国剩余定理
ll crt(){
ll ans = 0;
ll p = mod-1;
for(int i=0; i<4; i++)
{
ll tmp = p/prime[i];
ans = (ans + tmp*ksm(tmp,prime[i]-2,prime[i])%p*num[i]%p)%p;
}
return ans;
}
欧拉降幂
a b = { a b % ϕ ( p ) g c d ( a , p ) = 1 a b g c d ( a , p ) ≠ 1 , b < ϕ ( p ) a b % ϕ ( p ) + ϕ ( p ) g c d ( a , p ) ≠ 1 , b ≥ ϕ ( p ) a^b = \begin{cases} a^{b\%\phi(p)} & gcd(a,p)=1 \\ a^b & gcd(a,p)\ne1,b<\phi(p) \\ a^{b\%\phi(p)+\phi(p)} & gcd(a,p)\ne1,b\geq\phi(p) \\ \end{cases} ab=⎩ ⎨ ⎧ab%ϕ(p)abab%ϕ(p)+ϕ(p)gcd(a,p)=1gcd(a,p)=1,b<ϕ(p)gcd(a,p)=1,b≥ϕ(p)
ll euler(ll x){
ll res = x;
for(ll i=2; i*i<=x; i++)
if(x % i == 0){
res = res / i * (i - 1);
while(x % i == 0) x /= i;
}
if(x > 1) res = res / x * (x - 1);
return res;
}
欧拉筛
int prime[N+5],st[N+5];
int cnt=0;
void getprime(int n){
fer(i,2,n){
if(!st[i]) prime[cnt++]=i;
for(int j=0;prime[j]<=n/i;j++){
st[prime[j]*i]=true;
if(i%prime[j]==0)break;
}
}
}
拓展欧几里得
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
return a;
}
int x1,y1,gcd;
gcd=exgcd(b,a%b,x1,y1);
x=y1,y=x1-a/b*y1;
return gcd;
}
int main(){
int a,b,x,y,n;cin>>n;
while(n--){
cin>>a>>b;
exgcd(a,b,x,y);
cout<<x<<' '<<y<<endl;
}
return 0;
}
线性基
for(int i = 1;i<=n;i++){
ll tmp = a[i];
for(int j = 52;j>=0;j--){
if(((tmp >> j) & 1) == 0) continue;
if(p[j] == 0){
p[j] = tmp;
break;
}
else tmp ^= p[j];
}
}
矩阵快速幂
const int N = 3;
struct mat{
ll m[N][N];
void init(){
memset(m,0,sizeof m);
}
};
mat mul(mat x,mat y,ll mod){
mat res;
ll t = 0;
for(int i = 0; i <= n; i++){
for(int j = 0; j <= n; j++){
t = 0;
for(int k = 0; k <= n; k++){
t+= (x.m[i][k]%mod)*(y.m[k][j]%mod) % mod;
t%=mod;
}
res.m[i][j] = t % mod;
}
}
return res;
}
mat mat_qmi(mat a, ll k, ll mod){
mat res;
for(int i = 0; i <= n; i++){
for(int j = 0; j <= n; j++){
if(i == j) res.m[i][j] = 1;
else res.m[i][j] = 0;
}
}
while(k){
if(k&1) res = mul(res,a,mod);
a = mul(a,a,mod);
k>>=1;
}
return res;
}
ll qmi(ll x, ll b,ll mod){
ll res = 1;
while(b){
if(b&1) res = res*x%mod;
x=x*x%mod;
b>>=1;
}
return res;
}
ll euler(ll x){
ll res = x;
for(ll i=2; i*i<=x; i++)
if(x % i == 0){
res = res / i * (i - 1);
while(x % i == 0) x /= i;
}
if(x > 1) res = res / x * (x - 1);
return res;
}
int main(){
IOS;
int TT;
TT = 1;
cin >> TT;
while(TT--){
ll n,mod;
cin >> n >> mod;
mat init;
fer(i, 0, 2)fer(j, 0, 2) init.m[i][j] = 0;
init.m[0][0] =1; init.m[0][1] =1; init.m[0][2] = 0;
mat a;
a.m[0][0] = 0;a.m[0][1] = 1;a.m[0][2] = 0;
a.m[1][0] = 1;a.m[1][1] = 1;a.m[1][2] = 1;
a.m[2][0] = 0;a.m[2][1] = 0;a.m[2][2] = 1;
n = (ll)6*n;
mat tmp,ans;
tmp = mat_qmi(a,n,mod);
ans = mul(init,tmp,mod);
ll ans1 = ans.m[0][2];
ll MOD = euler(mod);
tmp = mat_qmi(a,n,MOD);
ans = mul(init,tmp,MOD);
ll t = ans.m[0][2];
ll ans2 = qmi(2,t,mod);
cout << ans1 <<" "<< ans2;
if(TT!=0) cout <<'\n';
}
return 0;
}
4.搜索
DFS
求连通块数量
int dx[]={0,0,1,-1,1,-1,1,-1};
int dy[]={1,-1,0,0,1,1,-1,-1};
int book[N][N];
int num,n,m;
char mp[N][N];
void dfs(int x,int y){
if(mp[x][y]=='*'||x<1||x>n||y<1||y>m||book[x][y]!=0)
return ;
book[x][y]=num;
for(int j=0;j<=7;j++){
int tx=x+dx[j];
int ty=y+dy[j];
if(mp[tx][ty]=='@'&&tx>=1&&tx<=n&&ty>=1&&ty<=m)
dfs(tx,ty);
}
}
int main(){
while(cin>>n>>m,n+m){
num=0;
memset(book,0,sizeof(book));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>mp[i][j];
for( int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='@'&&book[i][j]==0)
num++;
dfs(i,j);
}
}
cout<<num<<endl;
}
return 0;
}
5.动态规划
数位dp
int dp[15][15];
int a[15];
ll dfs(ll pos,bool limit,int pre,int lead){
if(pos == 0) return !lead;
if(!limit && dp[pos][pre] != -1 && !lead) return dp[pos][pre];
int up = limit ? a[pos] : 9;
ll tot = 0;
for(int i = 0;i<=up;i++){
if(!lead){
if(abs(i-pre)>=2) tot+=dfs(pos-1,limit && i == up,i,0);
}
else tot += dfs(pos-1,limit && i == up,i,i==0);
}
if(!lead && !limit) return dp[pos][pre] = tot;
return tot;
}
ll solve(ll x){
int pos = 0;
while(x){
a[++pos] = x%10;
x /=10;
}
return dfs(pos,1,-1,1);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll a,b;
cin >> a >> b;
memset(dp,-1,sizeof dp);
cout << solve(b)-solve(a-1);
return 0;
}
斜率优化dp
ll f[N];
ll a[N];
ll b[N];
int q[N];
int s[N];
ll l,n;
ll y(int i){
return f[i] + b[i]*b[i];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> l;
for(int i = 1; i <= n; i ++){
cin >> s[i];
s[i] += s[i-1];
}
for(int i = 0; i <= n; i ++){
a[i] = s[i] + i;
b[i] = a[i] + l + 1;
}
int hh = 0;
int tt = 0;
q[0] = 0;
for(int i = 1; i <= n; i ++){
while(hh < tt && (y(q[hh+1])-y(q[hh]))<=2*a[i]*(b[q[hh+1]]-b[q[hh]]))hh++;
f[i] = f[q[hh]] + (a[i] - b[q[hh]])*(a[i] - b[q[hh]]);
while(hh < tt && (y(q[tt])-y(q[tt-1]))*(b[i]-b[q[tt]])>=(y(i)-y(q[tt]))*(b[q[tt]]-b[q[tt-1]]))tt--;
q[++tt] = i;
//pf(f[i]);
}
cout << f[n];
return 0;
}
$f[i]={x_i+y_i\choose x_i} - \sum\limits_{x_j<=x_i\ ,\ y_j<=y_i\ ,\ j\neq i}{x_i-x_j+y_i-y_j\choose x_i-x_j}*f[j] $