常用易忘
ACM常见博弈论
头文件声明
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <list>
#define rep(i,m,n) for(int i=m;i<=n;i++)
#define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)
const int inf_int = 2e9;
const long long inf_ll = 2e18;
#define inf_add 0x3f3f3f3f
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pi acos(-1.0)
#define pii pair<int,int>
#define Lson L, mid, rt<<1
#define Rson mid+1, R, rt<<1|1
const int maxn=5e2+10;
using namespace std;
typedef vector<int> vi;
typedef long long ll;
typedef unsigned long long ull;
inline int read(){
int ra,fh;char rx;rx=getchar(),ra=0,fh=1;
while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-')
fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,
rx=getchar();return ra*fh;}
//#pragma comment(linker, "/STACK:102400000,102400000")
ll gcd(ll p,ll q){
return q==0?p:gcd(q,p%q);}
ll qpow(ll p,ll q){
ll f=1;while(q){
if(q&1)f=f*p;p=p*p;q>>=1;}return f;}
int dir[4][2]={
{
-1,0},{
1,0},{
0,-1},{
0,1}};
const int N = 1e7+5;
int main()
{
return 0;
}
数据类型范围
unsigned int 0~4294967295
int 2147483648~2147483647
unsigned long 0~4294967295
long 2147483648~2147483647
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:18446744073709551615
__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615
cin cout 速度慢问题
ios::sync_with_stdio(false);
用"\n"不用endl
欧拉筛法
for(int i = 2;i < 50005;i++){
if(a[i]) b[ci++] = i;
for(int j = 0;j < ci&&b[j]*i<50005;j++){
a[b[j]*i] = 0;
if(i%b[j] == 0) break;
}
}//欧拉筛法,不要太大,大于sqrt(x)后面的就没意义了,反而会是这道题超时
快速幂
LL quick_pow(LL a,LL b)
{
LL res = 1;
while(b)
{
if(b%2 != 0) res *= a;
a *= a;
b /= 2;
}
return res;
}
辗转相除法gcd和lcm
int gcd(int a,int b){
if(a%b == 0) return b;
else return gcd(b,a%b);
}
int gcd(int a,int b)///最大公因数,测试数据1e8,没有C++自带的__gcd(,)函数快
{
return (a%b==0)?b:gcd(b,a%b);
}
int lcm(int a,int b)///最小公倍数
{
return (a*b/gcd(a,b));
}
int main()
{
int a,b;
cin>>a>>b;
cout<<gcd(a,b)<<endl<<lcm(a,b)<<endl;
}
二进制枚举
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
for(int i = 0; i < (1<<n); i++) //从0~2^n-1个状态
{
for(int j = 0; j < n; j++) //遍历二进制的每一位
{
if(i & (1 << j))//判断二进制第j位是否存在
{
printf("%d ",j);//如果存在输出第j个元素
}
}
printf("\n");
}
return 0;
}
二分
int search(int array[], int n, int v)
{
int left, right, middle;
left = 0, right = n - 1;
while (left <= right)
{
middle = (left + right) >>1;
if (array[middle] > v)
{
right = middle - 1;
}
else if (array[middle] < v)
{
left = middle + 1;
}
else
{
return middle;
}
}
return -1;
}
kmp多串匹配模板
#include <bits/stdc++.h>
using namespace std;
char w[10000+10],t[1000000+10];
int next1[10000+10],ans;
void getnext(){
int wlen = strlen(w);
int j = 0,k = -1;
next1[0] = -1;
while(j < wlen){
if(k == -1 || w[k] == w[j]){
++k;
++j;
next1[j] = k;
}
else{
k = next1[k];
}
}
/* for(int i = 0;i <= wlen;i++){ */
/* printf("%d ",next1[i]); */
/* } */
}
void kmp(){
int wlen = strlen(w);
int tlen = strlen(t);
getnext();
int i = 0,j = 0;
while(j < tlen){
if(i == -1 || w[i] == t[j]){
i++;
j++;
if(i == wlen){
ans++;
i = next1[i];
}
}
else{
i = next1[i];
}
}
}
int main(){
int xx;
scanf("%d\n",&xx);
while(xx--){
memset(w,0,sizeof(w));
memset(t,0,sizeof(t));
scanf("%s",w);
scanf("%s",t);
ans = 0;
kmp();
printf("%d\n",ans);
}
return 0;
}
KMP最小循环节、循环周期:
https://blog.csdn.net/hao_zong_yin/article/details/77455285
定理:假设S的长度为len,则S存在最小循环节,循环节的长度L为len-next[len],子串为S[0…len-next[len]-1]。
(1)如果len可以被len - next[len]整除,则表明字符串S可以完全由循环节循环组成,循环周期T=len/L。
(2)如果不能,说明还需要再添加几个字母才能补全。需要补的个数是循环个数L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。
字符串哈希
p1220
#include<iostream>
#include<cstring>
using namespace std;
const int MaxNum = 20000000;
char ch[MaxNum];
bool lage[MaxNum]; //用于标记是否为相同的子串
int hashArray[256]; //存储n个字母转换成整数之后再转换成nc进制的数
int main() {
int n, nc;
while (cin >> n >> nc >> ch) {
int k = 0;
int len = strlen(ch); //注意此处
for (int i = 0; i < len; i++) {
if (hashArray[ch[i]] == 0) {
hashArray[ch[i]] = k++; //给nc个字母编号,如hashArray['a']=1
}
}
int ans = 0; //记录不同子串的种数
for (int i = 0; i <= len - n; i++) {
int sum = 0;
for (int j = i; j < i + n; j++) {
sum = sum * nc + hashArray[ch[j]];//将hashArray[]的nc进制数转换成一个十进制的整数sum
}
if (!lage[sum]) {
//未出现过为false
ans++;
lage[sum] = true; //出现过的为true
}
}
cout << ans << endl;
}
return 0;
}
树状数组
int lowbit(int x){
return x&(-x);
}
int update(int p,int x){
while(p <= 100010){
//数字n
bit[p] = bit[p] + x;
p = p + lowbit(p);
}
}
int query(int p){
int ans = 0;
while(0 < p){
ans = ans + bit[p];
p = p - lowbit(p);
}
return ans;
}
矩阵快速幂hdu1005 & LightOJ - 1070
hud1005
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
struct node{
ull x[2][2];
};
const int mod = 7;
node mux(node a,node b){
node t;
memset(t.x,0,sizeof(t.x));
for(int i = 0;i < 2;i++)
for(int j = 0;j < 2;j++)
for(int k = 0;k < 2;k++){
t.x[i][j] = (t.x[i][j]%mod + (a.x[i][k]*b.x[k][j])%mod)%mod;
}
return t;
}
node quick(ull n,node a){
node t;
memset(t.x,0,sizeof(t));
t.x[0][0] = t.x[1][1] = 1;
t.x[0][1] = t.x[1][0] = 0;
while(n){
if(n&1)
t = mux(t,a);
a = mux(a,a);
n=n>>1;
}
return t;
}
int main(){
ull a,b,n;
while(cin>>a>>b>>n){
if(a == 0 && b == 0 && n == 0){
exit(0);
}
if(n == 1 || n == 2){
cout<<1<<"\n";
continue;
}
node a1;
a1.x[0][0] = a;
a1.x[0][1] = 1;
a1.x[1][0] = b;
a1.x[1][1] = 0;
node ans = quick(n-2,a1);
cout<<(ans.x[0][0] + ans.x[1][0])%mod<<"\n";
}
return 0;
}
LightOJ - 1070
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long llu;
typedef unsigned int uint;
struct node{
llu s[2][2];
};
node mut(node a,node b){
node c;
memset(c.s,0,sizeof(c.s));
for(int i = 0;i < 2;i++)
for(int j = 0;j < 2;j++)
for(int k = 0;k < 2;k++)
c.s[i][j] = c.s[i][j]+ b.s[k][j]*a.s[i][k];
return c;
}
node quick(llu n,node p){
node q;
memset(q.s,0,sizeof(q.s));
q.s[0][1] = q.s[1][0] = 0;
q.s[1][1] = q.s[0][0] = 1;
while(n){
if(n&1)
q = mut(p,q);
p = mut(p,p);
n = n/2;
}
return q;
}
int main(){
llu t,cnt = 1;
llu x,y,z;
cin>>t;
while(t--){
cin>>x>>y>>z;
if(z == 1){
cout<<"Case "<<cnt++<<": "<<x<<"\n";
continue;
}
else if(z == 2){
cout<<"Case "<<cnt++<<": "<<x*x-2*y<<"\n";
continue;
}
else if(z == 0){
cout<<"Case "<<cnt++<<": "<<2<<"\n";
continue;
}
else{
node a1,b1;
a1.s[0][0] = x;
a1.s[1][0] = x*x-2*y;
a1.s[1][1] = 0;
a1.s[0][1] = 0;
b1.s[0][0] = x;
b1.s[1][0] = -1*y;
b1.s[0][1] = 1;
b1.s[1][1] = 0;
node ans = quick(z-2,b1);
cout<<"Case "<<cnt++<<": "<<a1.s[1][0]*ans.s[0][0] + a1.s[0][0]*ans.s[1][0]<<"\n";
}
}
return 0;
}
spfa hdu1874
#include <bits/stdc++.h>
using namespace std;
int dist[210],vis[210],cnt[210];//vis在对列的标志 cnt每个点的如队列次数
const int inf = 0x3f3f3f3f;
struct edge{
int v;
int cost;
edge(int _v = 0,int _cost=0):v(_v),cost(_cost){
};
};
vector<edge>e[210];
void addedge(int u,int v,int w)
{
e[u].push_back(edge(v,w));
}
bool spfa(int start,int n)
{
memset(vis,0,sizeof(vis));
for(int i = 0;i < n;i++)
dist[i] = inf;
vis[start] = 1;
dist[start] = 0;
queue<int>que;
while(!que.empty()) que.pop();
que.push(start);
memset(cnt,0,sizeof(cnt));
cnt[start] = 1;
while(!que.empty())
{
int u = que.front();
que.pop();
vis[u] = 0;
for(int i = 0; i < e[u].size();i++ )
{
int v = e[u][i].v;
if(dist[v] > dist[u] + e[u][i].cost){
dist[v] = dist[u] + e[u][i].cost;
if(!vis[v]){
vis[v] = 1;
que.push(v);
if(++cnt[v] > n)
return false;
//cnt[i]为入队列次数,用来判定是否存在负环回路
}
}
}
}
return true;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i = 0;i < n;i++)
e[i].clear();
int a,b,x;
for(int i = 0;i < m;i++){
scanf("%d%d%d",&a,&b,&x);
addedge(a,b,x);
addedge(b,a,x);
}
int start,end;
scanf("%d%d",&start,&end);
spfa(start,n);
if(dist[end] == inf)
printf("-1\n");
else
printf("%d\n",dist[end]);
}
return 0;
}
地杰斯特拉 p3371
#include <bits/stdc++.h>
using namespace std;
const int inf = 2147483647;
const int maxn = 100010;
struct qnode
{
int v,c;
qnode(int _v = 0,int _c = 0):v(_v),c(_c){
}
bool operator < (const qnode& a) const
{
return c > a.c;
}
};
struct edge{
int v,cost;
edge(int _v = 0,int _cost = 0):v(_v),cost(_cost){
}
};
vector <edge> e[maxn];
bool vis[maxn];
int dist[maxn];
//点的编号从1开始
//
void disa(int n,int start)
{
memset(vis,0,sizeof(vis));
for(int i = 1;i <= n;i++)
dist[i] = inf;
priority_queue<qnode>que;
while(!que.empty())
que.pop();
dist[start] = 0;
que.push(qnode(start,0));
qnode tmp;
while(!que.empty())
{
tmp = que.top();
que.pop();
int u = tmp.v;
if(vis[u])
continue;
vis[u] = 1;
for(int i = 0;i < e[u].size();i++)
{
int v = e[tmp.v][i].v;
int cost = e[u][i].cost;
if(!vis[v]&&dist[v] > dist[u]+cost)
{
dist[v] = dist[u] + cost;
que.push(qnode(v,dist[v]));
}
}
}
}
void addedge(int u,int v,int w)
{
e[u].push_back(edge(v,w));
}
int main(){
int n,m,s,v1,v2,w;
scanf("%d%d%d",&n,&m,&s);
for(int i = 0;i < m;i++)
{
scanf("%d%d%d",&v1,&v2,&w);
addedge(v1,v2,w);
/* addedge(v2,v1,w); */
}
disa(n,s);
for(int i = 1;i <= n;i++)
printf("%d ",dist[i]);
putchar('\n');
return 0;
}
二分图匹配hdu2063
#include <bits/stdc++.h>
using namespace std;
const int maxn = 510;
typedef long long ll;
vector<int>q[maxn];
int match[maxn],book[maxn];
int dfs(int u)
{
for(size_t i = 0;i < q[u].size();i++)
{
int t = q[u][i];
if(book[t] == 0)
{
book[t] = 1;
if(match[t] == 0 || dfs(match[t]))
{
match[t] = u;
return 1;
}
}
}
return 0;
}
int main(){
int k,n,m,a,b,sum = 0;
while(scanf("%d",&k)&&k){
for(int i = 0;i < maxn;i++)
q[i].clear();
memset(book,0,sizeof(book));
memset(match,0,sizeof(match));
scanf("%d%d",&n,&m);
for(int i = 0;i < k;i++)
{
scanf("%d%d",&a,&b);
q[a].push_back(b);
}
for(int i = 0;i <= n;i++)
match[i] = 0;
for(int i = 1;i <= n;i++)
{
memset(book,0,sizeof(book));
if(dfs(i))
sum++;
}
printf("%d\n",sum);
}
return 0;
}
P1435 lcs滚动数组优化
#include<bits/stdc++.h>
using namespace std;
int dp[2][5001];
char str1[5001],str2[5001];
int main()
{
int n;
scanf("%s",str1+1);
n = strlen(str1+1);
for(int i = 1; i <= n; i++)
str2[i] = str1[n-i+1];
for(int i = 1; i<=n; i++)
for(int j = 1; j <= n; j++)
if(str1[i]