【常用数据范围】
int ~ 2 * 10^9 long long 9 * 10^18
最近经常别 bool数组给忽悠,该bool的bool,该int的int。。
【gcd】
int gcd(int n,int m){
if(n%m==0)
return m;
else
return gcd(m,n%m);
}
【快速幂】
typedef long long ll;
ll pow_mod(ll x,ll n ,ll mod ){
ll res=1;
x=x%mod;
while(n){
if(n%2)
res=res*x%mod;
x=x*x%mod;
n/=2;
}
return res;
}
【图论算法】
-
【SPFA】
#include<iostream>
#include<vector>
#include<queue>
#include<cstdio>
#define INF 99999999
using namespace std;
const int maxn = 222;
int mapp[maxn][maxn],n,m;
int vis[maxn], dis[maxn];
int SPFA(int st,int end){
for(int i=0;i<n;i++){ // 初始化
dis[i] = INF; vis[i] = 0;//G[i].clear();
}
queue<int>Q;
dis[st] = 0;
vis[st] = 1; //起始点距离为0, 标记上
Q.push(st);
while(!Q.empty()){
int vex = Q.front(); Q.pop();
vis[vex] = 0; //
for(int i=0;i<n;i++){
if( dis[i] > mapp[vex][i] + dis[vex]){
dis[i] = mapp[vex][i] + dis[vex];
if(!vis[i]){
vis[i] = 1;
Q.push(i);
}
}
}
}
return dis[end];
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
mapp[i][j] = INF;
int a,b,c;
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
if(c < mapp[a][b])
mapp[a][b] = mapp[b][a] = c;
}
int s,e;
scanf("%d%d",&s,&e);
int ans = SPFA(s,e);
if(ans < INF) printf("%d\n",ans);
else
printf("-1\n");
}
}
-
【Dijkstra】
#include<iostream>
#include<vector>
#include<queue>
#include<cstdio>
#include<cstring>
#define INF 0xfffffff
using namespace std;
const int maxn = 222;
int n,m;
int map[maxn][maxn];
int dis[maxn];
bool vis[maxn];
int dijkstra(int st,int end){
memset(vis,0,sizeof(vis));
vis[st] = 1;
for(int i=0;i<n;i++){
dis[i] = map[st][i];
}
dis[st] = 0;
for(int num = 1;num<n;num++){ //找到其余的n-1个点
int tmp = INF, k = -1;
for(int i=0;i<n;i++){
if(!vis[i] && tmp > dis[i]){
tmp = dis[i];
k = i;
}
}
if(k == -1) break; // 当前没有找到最短的节点
vis[k] = true;
for(int i=0;i<n;i++)
if(!vis[i] && dis[i] > dis[k] + map[k][i] )
dis[i] = dis[k] + map[k][i];
}
return dis[end];
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
map[i][j] = (i == j)? 0:INF;
int a,b,c;
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
if(c< map[a][b])
map[a][b] = map[b][a] = c;
}
int s,e; scanf("%d%d",&s,&e);
int ans = dijkstra(s,e);
if(ans == INF)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}
- 【Dijkstra堆优化 (n + m)logn】
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#define MAXN 200 + 10
#define INF 0xffffff
using namespace std;
struct node{
int v, len;
bool operator < (const node & t) const{
return len > t.len;
}
node(int v = 0, int len = 0):v(v), len(len){}
};
vector<node> G[MAXN];
bool vis[MAXN];
int dis[MAXN];int n,m;
void Init(int n){
for(int i = 0; i <= n; i++){
G[i].clear();
}
}
int dijstra_heap(int s,int t){
for(int i = 0; i <= n; i++){
vis[i] = false;
dis[i] = INF;
}
priority_queue<node>Q;
dis[s] = 0;
Q.push(node(s,0));
while(!Q.empty()){
node now = Q.top();
Q.pop();
int v = now.v;
if(vis[v]) continue;
vis[v] = true;
for(int i=0;i<G[v].size();i++){
int v2 = G[v][i].v; int len = G[v][i].len;
if(!vis[v2] && dis[v] + len <dis[v2]){
dis[v2] = dis[v] + len ;
Q.push(node(v2,dis[v2])); //讲 dis[v2]放入堆中,利用logn的效率找到
//距离最短的节点
}
}
}
return dis[t];
}
int main(){
int v1, v2, x, s, t;
while(scanf("%d%d", &n, &m) != EOF){
Init(n);
for(int i = 0; i < m; i++){
scanf("%d%d%d", &v1, &v2, &x);
G[v1].push_back(node(v2, x));
G[v2].push_back(node(v1, x));
}
scanf("%d%d", &s, &t);
int ans = dijstra_heap(s, t, n);
if(ans == INF)
printf("-1\n");
else
printf("%d\n", ans);
}
return 0;
}
-
【Floyd-Warshall算法 n ^ 3】
#include<iostream>
#include<vector>
#include<queue>
#include<cstdio>
#define INF 0xfffffff
using namespace std;
const int maxn = 222;
int n,m;
int map[maxn][maxn];
void floyed(){ //k ,i ,j
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(map[i][j] > map[i][k] + map[k][j])
map[i][j] = map[i][k] + map[k][j];
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i == j) map[i][j] = 0;
else map[i][j] = INF;
int a,b,c;
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
if(c < map[a][b]) //重边
map[a][b] = map[b][a] = c;
}
int s,e; scanf("%d%d",&s,&e);
floyed();
if(map[s][e] == INF)
printf("-1\n");
else
printf("%d\n",map[s][e]);
}
return 0;
}
-
【Kruskal算法 最小生成树】
struct node{
int v1,v2,len;
}edge[maxn];
void init(){
for(int i=1;i<=n;i++){
father[i] = i;
}
}
int Find(int x){
int r= x;
while(r != father[r])
r = father[r];
while(x != r){
int tmp = father[x];
father[x] = r;
x = tmp;
}
return r;
}
int Find(int x){
if(x == father[x]) return x;
else
return father[x] = Find(father[x]);
}
void Union(int x,int y){
int xr = Find(x);
int yr = Find(y);
if(xr == yr) return;
else
father[xr] = yr;
}
void Kruskal(){ // Kruskal 算法
int edgenum=0;
for(int i=0;i<len&& edgenum!=n-1;i++){
if(Find(edge[i].v1)!=Find(edge[i].v2)){
ans += edge[i].len;
Union(edge[i].v1,edge[i].v2);
edgenum++;
}
}
}
-
【PRIM 最小生成树】
注意,不能判环
#define INF 0x3f3f3f3f
struct node{
int v,len;
node(int v=0, int len = 0):v(v),len(len){}
};
vector <node> G[maxn];
int vis[maxn];
int dis[maxn];
void init(){
for(int i=0;i<maxn;i++){
vis[i]=0;
G[i].clear();
dis[i]=INF;
}
}
int prim(int s){
vis[s]=1;
int ans=0;
for(int i=0;i<G[s].size();i++){
int vex = G[s][i].v;
dis[vex] = min(G[s][i].len,dis[vex]); //判重边
}
for(int nodeNum=0;nodeNum<n-1;nodeNum++){
int tmpMin=INF;
int addNode=-1;
for(int i=1;i<=n;i++){ //从1 到 n 的城市标号
if(!vis[i]&&dis[i]<tmpMin){
tmpMin=dis[i];
addNode = i;
}
}
if(addNode==-1) {
return -1;
}
ans+=tmpMin;
vis[addNode]=1;
for(int i=0;i<G[addNode].size();i++){
int vex = G[addNode][i].v;
if(!vis[vex]&&G[addNode][i].len<dis[vex])
dis[vex] = G[addNode][i].len;
}
}
return ans;
}
-
【匈牙利算法】二分图最大匹配
int findpath(int k){
for(int i=head[k];i!=-1;i=edge[i].next){
int v = edge[i].to;
if(!inpath[v]){
inpath[v]=1;
if(match[v]==-1||findpath(match[v])){
match[v]=k;return true;
}
}
}
return false;
}
void hungary(){
int ans=0;
for(int i=1;i<=n;i++){
memset(inpath,0,sizeof(inpath));
if(findpath(i)){ //寻找增广路
ans++;
}
}
cout<<ans<<endl;
}
void init(){
memset(head,-1,sizeof(head));
memset(match,-1,sizeof(match));
edgeNum=0;
}
-
【tarjan】求强连通分量
#include<cstdio> // 顶点从0 - n-1
#include<algorithm>
#include<vector>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define INF 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int N = 100010;
int low[N];//当前能回溯到的栈中最小的次序号
int pre[N]; // 记录当前节点的次序号。(时间戳)
int scc[N];//记录节点所属强连通分量
stack<int>st;//栈中储存当前未处理的节点(访问了,但并没有划分为连通分量)
int dfs_num;//次序号
int cnt;//强连通分量的编号 1 ~ maxNumberOfSCC
int n,m;
int dis[N];
vector<int>V[N],G[N];
void init(){
mem(low,0);mem(pre,0);mem(scc,0);
dfs_num = 0; cnt = 0;
while(!st.empty()) st.pop();
for(int i=0;i<=n;i++){
V[i].clear();G[i].clear();
}
}
void tarjan(int x){
pre[x] = low[x] = ++dfs_num;
st.push(x);
for(int i=0;i<V[x].size();i++){
int v = V[x][i];
if(!pre[v]){//没有访问过
tarjan(v);
low[x] = min(low[x],low[v]);
}
else if(!scc[v]){// 访问过了,但是没有划分联通分量,
//也就是在栈中
low[x] = min(low[x],pre[v]); // pre[v],v节点的时间戳
}
}
if(low[x] == pre[x] ){//当前的次序号等于 能回溯到的最小次序号
//说明找到了”根“节点
cnt++;
while(1){
int tmp = st.top(); st.pop();
scc[tmp] = cnt;
if(tmp == x) break;
}
}
}
int bfs(int x){
queue<int>Q;
Q.push(x);
mem(dis,-1);
dis[x] = 0;
while(!Q.empty()){
int u = Q.front();Q.pop();
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(dis[v] == -1){
dis[v] = dis[u] + 1;
if(v == scc[n-1]) return dis[v];
Q.push(v);
}
}
}
return dis[scc[n-1]];
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
init();
int a,b;
for(int i=0;i<m;i++){
scanf("%d%d",&a,&b);
V[a].push_back(b);
}
for(int i=0;i<n;i++){
if(!pre[i])
tarjan(i);//缩点
}
for(int i=0;i<n;i++){ //重新构图
for(int j=0;j<V[i].size();j++){
int v = V[i][j];
if(scc[i] != scc[v])
G[scc[i]].push_back(scc[v]);
}
}
int ans = bfs(scc[0]);
printf("%d\n",ans);
}
}
数据结构
-
【线段树点更新,区间查询】
#define L(m) m<<1
#define R(m) m<<1|1
const int maxn = 1000000+1;
int num[maxn];
struct node{
int l,r,sum;
}tree[maxn<<2]; //开4倍数组
void Build(int m,int l,int r){
tree[m].l=l; tree[m].r=r; //赋初值
if(tree[m].l==tree[m].r)
{
tree[m].sum=num[l]; return ;//不要忘了return
}
int mid = (tree[m].l+tree[m].r)>>1;
Build(L(m),l,mid); //递归构造左右子树
Build(R(m),mid+1,r);
tree[m].sum = tree[L(m)].sum+tree[R(m)].sum; //回溯,将子节点的sum加到父节点上
}
void Update(int m,int a,int x){
if(tree[m].l==a && tree[m].r==a){
tree[m].sum+=x; return ; //这个return 忘了写找了好久的错
}
int mid = (tree[m].l+tree[m].r)>>1;
if(mid>=a)
Update(L(m),a,x);
else
Update(R(m),a,x);
tree[m].sum=tree[L(m)].sum+tree[R(m)].sum;
}
int Query(int m,int l,int r){
if(tree[m].l==l && tree[m].r==r){
return tree[m].sum;
}
int mid = (tree[m].l+tree[m].r)>>1;
if(mid>=r) //这里也可以写成 if else if else
return Query(L(m),l,r);
if(mid<l)
return Query(R(m),l,r);
return Query(L(m),l,mid)+Query(R(m),mid+1,r);
}
-
【线段树区间修改,点查询】
#define L(m) m<<1
#define R(m) m<<1|1
using namespace std;
const int maxn =100000+10;
typedef long long ll;
ll num[maxn];
struct node{
ll l,r,sum;
ll add;
}tree[maxn<<2];
void pushup(ll m){
tree[m].sum = tree[L(m)].sum + tree[R(m)].sum;
}
void pushdown(ll m){
if(tree[m].add){
ll tmp = tree[m].add;
tree[L(m)].sum += (tree[L(m)].r-tree[L(m)].l+1)*tmp;
tree[R(m)].sum += (tree[R(m)].r-tree[R(m)].l+1)*tmp;
tree[L(m)].add +=tmp; //所有的都是 += ;
tree[R(m)].add +=tmp;
tree[m].add = 0;
}
}
void Update(ll m,ll l,ll r,ll x){
if(tree[m].l >=l && tree[m].r <=r){
tree[m].add += x; //注意这里是+= 不是 =
tree[m].sum += (tree[m].r - tree[m].l + 1) *x;
return ;
}
pushdown(m);
ll mid = (tree[m].l + tree[m].r)>>1; //这里取中间取得是当前节点左右区间的中点
if(mid>=r) 如果要更新的区间在左边
Update(L(m),l,r,x);
else if(mid<l)
Update(R(m),l,r,x);
else{
Update(L(m),l,mid,x);
Update(R(m),mid+1,r,x);
}
pushup(m);
}
ll Query(ll m,ll l,ll r){
if(tree[m].l==l && tree[m].r==r){
return tree[m].sum;
}
pushdown(m);
ll mid = (tree[m].l+ tree[m].r)>>1;
if(mid>=r)
return Query(L(m),l,r);
if(mid<l)
return Query(R(m),l,r); //这里也可以写成 if else else if
return Query(L(m),l,mid)+Query(R(m),mid+1,r);
}
void Build(ll m,ll l,ll r){
tree[m].l = l,tree[m].r = r;
tree[m].add=0; //不要忘了初始化
if(l == r){
tree[m].add = 0;
tree[m].sum = num[l];
return ;
}
int mid = (l + r)>>1;
Build(L(m),l,mid);
Build(R(m),mid+1,r);
pushup(m);
}
-
【线段树模板2,单点更新】
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 50005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2];
void Pushup(int rt){
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void Build(int l,int r,int rt){
if(l == r){
scanf("%d",&sum[rt]);
}
else{
int m = (l + r)>>1;
Build(lson);
Build(rson);
Pushup(rt);
}
}
void Update(int p,int add,int l,int r,int rt){
if(l == r){
sum[rt] += add;
}
else{
int m = (l + r)>>1;
if(p <=m)
Update(p,add,lson);
else
Update(p,add,rson);
Pushup(rt);
}
}
int Query(int L,int R,int l,int r,int rt){ //L ,R为查询范围
if(L <= l && r <=R){
return sum[rt];
}
int m = (l + r)>>1;
int ans = 0;
if(L<=m)
ans += Query(L,R,lson);
if(R>m)
ans += Query(L,R,rson);
return ans;
}
int main(){
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++){
printf("Case %d:\n",cas);
int n,a,b;
scanf("%d",&n);
Build(1,n,1);
char s[10];
while(scanf("%s",s)!=EOF){
if(s[0] == 'E') break;
if(s[0] == 'A'){
scanf("%d%d",&a,&b);
Update(a,b,1,n,1);
}
else if(s[0] == 'S'){
scanf("%d%d",&a,&b);
Update(a,-b,1,n,1);
}
else if(s[0] == 'Q'){
scanf("%d%d",&a,&b);
printf("%d\n",Query(a,b,1,n,1));
}
}
}
}
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 50005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2];
void Pushup(int rt){
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void Build(int l,int r,int rt){
if(l == r){
scanf("%d",&sum[rt]);
}
else{
int m = (l + r)>>1;
Build(lson);
Build(rson);
Pushup(rt);
}
}
void Update(int p,int add,int l,int r,int rt){
if(l == r){
sum[rt] += add;
}
else{
int m = (l + r)>>1;
if(p <=m)
Update(p,add,lson);
else
Update(p,add,rson);
Pushup(rt);
}
}
int Query(int L,int R,int l,int r,int rt){ //L ,R为查询范围
if(L <= l && r <=R){
return sum[rt];
}
int m = (l + r)>>1;
int ans = 0;
if(L<=m)
ans += Query(L,R,lson);
if(R>m)
ans += Query(L,R,rson);
return ans;
}
int main(){
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++){
printf("Case %d:\n",cas);
int n,a,b;
scanf("%d",&n);
Build(1,n,1);
char s[10];
while(scanf("%s",s)!=EOF){
if(s[0] == 'E') break;
if(s[0] == 'A'){
scanf("%d%d",&a,&b);
Update(a,b,1,n,1);
}
else if(s[0] == 'S'){
scanf("%d%d",&a,&b);
Update(a,-b,1,n,1);
}
else if(s[0] == 'Q'){
scanf("%d%d",&a,&b);
printf("%d\n",Query(a,b,1,n,1));
}
}
}
}
-
【线段树模板2,区间修改】
#include <cstdio>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL long long
const int maxn = 111111;
LL add[maxn<<2];
LL sum[maxn<<2];
void PushUp(int rt) {
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void PushDown(int rt,int m) {
if (add[rt]) {
add[rt<<1] += add[rt];
add[rt<<1|1] += add[rt];
sum[rt<<1] += add[rt] * (m - (m >> 1));
sum[rt<<1|1] += add[rt] * (m >> 1);
add[rt] = 0;
}
}
void build(int l,int r,int rt) {
add[rt] = 0;
if (l == r) {
scanf("%lld",&sum[rt]);
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int L,int R,int c,int l,int r,int rt) {
if (L <= l && r <= R) {
add[rt] += c;
sum[rt] += (LL)c * (r - l + 1);
return ;
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
if (L <= m) update(L , R , c , lson);
if (m < R) update(L , R , c , rson);
PushUp(rt);
}
LL query(int L,int R,int l,int r,int rt) {
if (L <= l && r <= R) {
return sum[rt];
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
LL ret = 0;
if (L <= m) ret += query(L , R , lson);
if (m < R) ret += query(L , R , rson);
return ret;
}
int main() {
int N , Q;
scanf("%d%d",&N,&Q);
build(1 , N , 1);
while (Q --) {
char op[2];
int a , b , c;
scanf("%s",op);
if (op[0] == 'Q') {
scanf("%d%d",&a,&b);
printf("%lld\n",query(a , b , 1 , N , 1));
} else {
scanf("%d%d%d",&a,&b,&c);
update(a , b , c , 1 , N , 1);
}
}
return 0;
}
【KMP】
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn =1000005;
const int maxb =10005;
int a[maxn],b[maxb];
int nextv[maxb];
void get_next(int b[],int m){ //求模式串的 next数组
int i=0;//前缀
nextv[0]=-1;
int j=-1;//后缀
while(i<m){
if(j==-1||b[i]==b[j]){
i++; j++;
if(b[i]==b[j]) //遇到相同元素的优化
nextv[i]=nextv[j];
else
nextv[i]=j;
}
else
j=nextv[j];
}
}
int KMP(int n,int m){
int i=0;
int j=0; int cnt = 0;
while(i<n&&j<m){
if(j==-1||a[i]==b[j]){
i++;j++;
}
else{
j=nextv[j];
}
/* //find match's times
if(j==m){
cnt++;
j = nextv[j];
}
*/
}
if(j==m){ //只有匹配出结果j才能==m
// cout<<"i: "<<i<<" "<<j<<endl;
return i-m+1;
}
else return -1;
}
int main(){
int T,n,m;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<m;i++){
scanf("%d",&b[i]);
}
get_next(b,m); //模式串 partern
int ans=KMP(n,m);
cout<<ans<<endl;
}
return 0;
}
AC自动机
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct node{
node *next[26];
int count ; //记录
node* fail;
node(){
count = 0;
fail = NULL;
memset(next,0,sizeof(next));
}
}*q[5000000];
int head,tail;
char str[1000010];
node *root;
void insert(char *s){ //构建trie
int len = strlen(s);
node *p = root;
for(int i=0;i<len;i++){
int index = s[i]-'a';
if(!p->next[index])
p->next[index] = new node;
p=p->next[index];
}
p->count++;
}
void build_ac_automation(){ //初始化fail指针
q[tail++] = root;
while(head<tail){
node *p = q[head++];
node *tmp = NULL;
for(int i=0;i<26;i++){
if(p->next[i] != NULL){
if(p == root)//首元素必须指根
p->next[i]->fail = root;
else{
tmp = p->fail; //失败指针(跳转指针)
while(tmp != NULL){
if(tmp->next[i] != NULL){//找到匹配
p->next[i]->fail = tmp->next[i];
break;
} //如果没找到,则继续向上一个失败指针找
tmp = tmp->fail;
}
if(tmp == NULL) //为空 则从头匹配
p->next[i]->fail = root;
}
q[tail++] = p->next[i];//下一层入队
}
}
}
}
int query(){
int len = strlen(str);
node *p = root;
int cnt = 0;
for(int i=0;i<len;i++){
int index = str[i]-'a';
while(p->next[index] == NULL && p!=root)
p = p->fail;
p = p->next[index];
if(p == NULL)
p = root;
node *tmp = p;//tmp 动 , p不动。
while(tmp != root && tmp->count != -1){
cnt += tmp->count;
tmp->count = -1;
tmp = tmp ->fail;
}
}
return cnt;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
head= tail = 0;
root = new node;
int n;
scanf("%d",&n);
char s[10010];
for(int i=0;i<n;i++){
scanf("%s",s);
insert(s);
}
build_ac_automation();
scanf("%s",str);
int ans = query();
printf("%d\n",ans);
}
return 0;
}
最小表示法
int minRepresentation(char *s){
int i=0,j=1,k=0;
while(i<len && j<len && k<len){
int tmp = s[(i + k)%len] - s[(j + k)%len];
if(tmp == 0) k++; //相等
else{
if(tmp > 0) //改成 tmp > 0 就是最大表示法了
i += k+1; // i = i + k + 1;
else
j += k+1;
if(i == j) j++;
k = 0;
}
}
return min(i,j); //返回字典序最小的下标
}
【杂项】
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
//字符串 转 数字 sscanf("12.24","%lf",&num);
//或者 atoi(char *s); atof(char *s)//stdlib.h
//数字转字符串
//sprintf(char *s,"%d",num)
int main()
{
double t;
sscanf("12.24","%lf",&t);
cout<<t<<endl;
double num1 = atof("12");
int num2 = atoi("123");
cout<<num1<<" "<<num2<<endl;
char s[1010];
sprintf(s,"%.2lf",t);
cout<<s<<endl;
return 0;
}
计算几何模板
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const double eps = 1e-10;
int dcmp(double x){
if(fabs(x) < eps) return 0;
return x < 0 ? -1:1;
}
struct Point{
double x,y;
Point(double x = 0,double y = 0):x(x),y(y){}
bool operator <(const Point& b)const{
return x < b.x || (x == b.x && y < b.y);
}
bool operator == (const Point &b)const {
return dcmp(x - b.x) == 0&& dcmp(y - b.y) == 0;
}
};
typedef Point Vector ;
// 求向量 (x,y)的极角,atan2(y,x); -- C标准库
Vector operator + (Vector A,Vector B){
return Vector(A.x + B.x , A.y + B.y);
}
Vector operator - (Vector A,Vector B){
return Vector(A.x - B.x , A.y - B.y);
}
Vector operator * (Vector A,double p){
return Vector(A.x*p , A.y*p);
}
Vector operator / (Vector A,double p){
return Vector(A.x/p , A.y/p);
}
/*
bool operator < (const Point&a , const Point&b){
}
*/
double Dot(Vector A,Vector B){ //求点积 .
return A.x * B.x + A.y * B.y;
}
double Length(Vector A){ //求向量长度
return sqrt(Dot(A,A));
}
double Angle(Vector A,Vector B){
return acos(Dot(A,B) / Length(A) / Length(B)); //求出cos ,再用acos求出角度、
}
double Cross(Vector A , Vector B){ //求叉积
return A.x*B.y - A.y* B.x;
}
double Area2(Point A,Point B,Point C){
return Cross(B-A,C-A);
}
//向量旋转 公式 x' = x * cosa - y * sina, y' = x * sina + y * cosa;
Vector Rotate(Vector A,double rad){
return Vector(A.x * cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y * cos(rad));
}
//计算向量的 单位 法线。
Vector Normal(Vector A){
double L = Length(A);
return Vector(-A.y / L , A.x /L);
}
//计算交点, 调用前确保 Cross(v,w) 非0
//设 直线分别为 P + tv 和 Q + tw;
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w){
Vector u = P-Q;
double t = Cross( w , u) / Cross( v , w );
return P + v * t;
}
//点到直线距离
double DistanceToLine(Point P, Point A,Point B){ //叉积 除以 底
Vector v1 = B - A, v2 = P - A;
return fabs(Cross(v1,v2)) / Length(v1); //不取绝对值,则为有向距离
}
//点到线段的距离
double DistanceToSegment(Point P, Point A, Point B){
if(A == B) return Length(P - A) ; // AB重合,成点对点长度
Vector v1 = B - A, v2 = P - A, v3 = P - B;
if(dcmp(Dot(v1,v2)) < 0) return Length(v2); // == 0 的时候是垂直的,小于零在二三象限; 即离A近;
else if(dcmp(Dot(v1,v2)) > 0) return Length(v3); //大于零 一四象限。
else return fabs(Cross(v1,v2)) / Length(v1); // 垂直的情况,直接用叉积来求了。
}
Point GetLineProjection(Point P,Point A,Point B){ //获得P在线段AB上投影的节点。
// AB向量 A + tv , Q 即投影点 A + t0v ,
// PQ 垂直于AB ,Dot()应该为0. 所以 Dot(v , P - (A + t0v))'
// 分配率 Dot(v , P - A) - t0 * Dot(v,v) = 0;
Vector v = B - A;
return A + v * (Dot(v , P - A) / Dot(v,v));
}
//判断线段相交
// 规范相交 : 两线段恰好有一个公共点。且不在端点。
// 充要条件: 每条线段两个端点都在另一条线段的两侧。(叉积符号不同)
bool SegmentProperIntersection(Point a1, Point a2,Point b1,Point b2){
double c1 = Cross(a2-a1 , b1 -a1) , c2 = Cross(a2-a1 , b2 -a1) ;
double c3 = Cross(b2-b1 , a1 -b1) , c2 = Cross(b2-b1 , a2 -b1) ;
return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0 ;
}<span style="display: none; width: 0px; height: 0px;" id="transmark"></span>
//判断点p是否在线段a1a2上
bool OnSegment(Point p,Point a1,Point a2)
{
return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}
Point getD(Point A, Point B, Point C){ // A B C 逆时针给出
Vector v1 = C - B;
double a1 = Angle(A - B , v1);
v1 = Rotate(v1, a1 / 3);
Vector v2 = B - C;
double a2 = Angle(A-C,v2);
v2 = Rotate(v2 , -a2 / 3);
return GetLineIntersection(B,v1,C,v2);
}
Point read_Point(){
Point tmp;
scanf("%lf%lf",&tmp.x,&tmp.y);
return tmp;
}
int main(){
int T;
Point A,B,C,D,E,F;
scanf("%d",&T);
while(T--){
A = read_Point();
B = read_Point();
C = read_Point();
D = getD(A ,B, C) ; //逆时针给出,
E = getD(B ,C, A) ;
F = getD(C ,A, B) ;
printf("%.6f %.6f %.6f %.6f %.6f %.6f\n",D.x,D.y,E.x,E.y,F.x,F.y);
}
return 0 ;
}
</pre><p></p><pre code_snippet_id="1614361" snippet_file_name="blog_20161021_21_2365810" name="code" class="cpp">//约数枚举O(sqrt(n))
vector<int> divisor(int n){
vector<int>res;
for(int i=1;i*i <=n;i++){
if(n % i ==0){
res.push_back(i);
if(i!= n/i)
res.push_back(n/i);
}
}
return res;
}
const int maxn = 10000000 + 10;
bool isprime[maxn];
int prime[maxn];int cnt = 0;
void Prime(){
prime[2] = 0; cnt = 0;
for(int i=2;i<maxn;i++){
if(!isprime[i]){
prime[cnt++] = i;
for(int j=i*2;j<maxn;j+=i){
isprime[j] = 1;
}
}
}
}
最长回文的Manchester算法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 110010;
char s[maxn];
char s2[maxn*2];
int p[maxn *2]; // mx == p[id] + id , 回文右边界
// id 回文中心
void Man(){
memset(p,0,sizeof(p));
int mx = 0 ,id=0;
for(int i=0;s2[i]!='\0';i++){
p[i] = mx > i ?min(p[2*id-i],mx-i ):1;
while(s2[i+p[i]] == s2[i-p[i]]) p[i]++;
if(p[i] + i > mx){
mx = p[i] + i;
id = i;
}
}
}
int main(){
while(scanf("%s",s)!=EOF){
s2[0] = '$';
int len = strlen(s);
int c = 1;//注意这里 == 1
for(int i=0;i<len;i++){
s2[c++] = '#';
s2[c++] = s[i];
}
s2[c++] ='#';
s2[c] = '\0';
Man();
int ans = 1;
for(int i=0;i<c;i++)
ans = max(ans,p[i]);
printf("%d\n",ans-1);
}
return 0;
}
卡特兰数递推公式:
h(n)=h(n-1)*(4*n-2)/(n+1)
小模块整理
ll strToll(string tmp){
int len = tmp.length();
//cout<<len<<"jj"<<endl;
ll ans = 0;ll cc = 1;
for(int i=len-1;i>=0;i--){
ans += (tmp[i]-'0') * cc;
cc*=10;
}
return ans;
}