竞赛结束了,现在将竞赛所有的内容进行一下汇总,并将所有能用的模版代码写于此,PPT中有详细的算法思路的解释,所以在此不再赘述,只有模版代码,务必记熟!
贪心没有模版,就不写了QAQ
二分模版也不是很难记,也不写了QAQ
从三分开始
三分(求单峰函数最值):
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n;
double l,r;
struct function{
int mi;
double xi;
}a[1000001];
double f(double x){
double ans = 0;
for(int i = 1;i <= n + 1; i++){
ans = ans + a[i].xi * pow(x,a[i].mi);
}
return ans;
}
int main(){
scanf("%d" ,&n);
scanf("%lf %lf" ,&l,&r);
int k = n;
for(int i = 1;i <= n + 1; i++){
a[i].mi = k;
k--;
}
for(int i = 1;i <= n + 1; i++){
scanf("%lf" ,&a[i].xi);
}
double smid,emid;
double st = l,ed = r;
while(ed - st > 0.00001){
double mid = (st + ed) / 2;
smid = mid;
emid = mid + 0.000001;
if(f(smid) > f(emid)){
ed = emid;
}
if(f(smid) < f(emid)){
st = smid;
}
if(f(smid) == f(emid)){
st = smid;
ed = emid;
}
}
printf("%.5lf" ,st);
return 0;
}
快速幂(配上取模):
#include<cstdio>
using namespace std;
long long int n,p,k;
long long int mi(long long int x,long long int y,long long int z){
long long int res = 1;
while(y){
if(y % 2 == 1) res = res * x % z;
x = x * x % z;
y = y / 2;
}
return res;
}
int main()
{
scanf("%lld %lld %lld" ,&n,&p,&k);
printf("%lld^%lld mod %lld=%lld" ,n,p,k,mi(n,p,k) % k);
return 0;
}
ST表(这个东西不但原理复杂还不好记,要多看看)
一维:
#include<cstdio>
#include<algorithm>
using namespace std;
int a[1000001] = { };
int ans[1000001] = { };
int dp[100501][17] = { };
int que[100501] = { };
int m,n;
int query(int l,int r){
int k = que[r - l + 1];
return max(dp[l][k],dp[r - (1 << k) + 1][k]);
}
int main(){
scanf("%d %d" ,&n,&m);
for(int i = 1;i <= n; i++){
scanf("%d" ,&a[i]);
}
for(int i = 1;i <= n; i++){
dp[i][0] = a[i];
}
for(int j = 1;1 << j <= n; ++j){
for(int i = 1;i + (1 << j) - 1 <= n; ++i){
dp[i][j] = max(dp[i][j - 1],dp[i + (1 << (j - 1))][j - 1]);
}
}
int k = 0;
for(int i = 1;i <= n; ++i){
if((1 << k) <= i) k++;
que[i] = k - 1;
}
int h = 1;
for(int i = 1;i <= m; i++){
int x,y;
scanf("%d %d" ,&x,&y);
printf("%d\n" ,query(x,y));
}
return 0;
}
二维:
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int a,b,n;
int ma[1010][1010][9] = { },mi[1010][1010][9] = { };
int que[1001] = { };
int ans[1010][1010] = { };
int ac[1010][1010] = { };
int max4(int a,int b,int c,int d){
return max(a,max(b,max(c,d)));
}
int min4(int a,int b,int c,int d){
return min(a,min(b,min(c,d)));
}
int l[1001] = { };
int query(int x,int y){
int k = que[y - x + 1];
int p,q;
p=max4(ma[x][y][k],ma[x + n - (1 << k)][y][k],ma[x][y + n - (1 << k)][k],ma[x + n - (1 << k)][y + n - (1 << k)][k]);
q=min4(mi[x][y][k],mi[x + n - (1 << k)][y][k],mi[x][y + n - (1 << k)][k],mi[x + n - (1 << k)][y + n - (1 << k)][k]);
return p - q;
}
int main(){
scanf("%d %d %d" ,&a,&b,&n);
for(int i = 1;i <= a; i++){
for(int j = 1;j <= b; j++){
scanf("%d" ,&ac[i][j]);
}
}
for(int i = 1;i <= a; i++){
for(int j = 1;j <= b; j++){
ma[i][j][0] = mi[i][j][0] = ac[i][j];
}
}
l[0]=1;
for(int i=1;i<=18;i++){
l[i]=l[i-1] * 2;
}
int p = 0;
while(l[p + 1] <= n){
p++;
}
for(int k = 1;k <= p; k++){
for(int i = 1;i + (1 << k) - 1 <= a; i++){
for(int j = 1;j + (1 << k) - 1 <= b; j++){
ma[i][j][k]=max4(ma[i][j][k-1],ma[i + (1 << (k - 1))][j][k-1],
ma[i][j + (1 << (k - 1))][k-1],ma[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]);
mi[i][j][k]=min4(mi[i][j][k - 1],mi[i + (1 << (k - 1))][j][k - 1],
mi[i][j + (1 << (k - 1))][k-1],mi[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]);
}
}
}
int k = 1; //原来是k = 0;
for(int i = 1;i <= n; ++i){
if((1 << k) <= i) k++;
que[i] = k - 1;
}
int xiao = 1e10 - 1;
for(int i = 1;i + n - 1 <= a; i++){
for(int j = 1;j + n - 1<= b; j++){
if(query(i,j) < xiao) xiao = query(i,j); ///!
}
}
printf("%d\n" ,xiao);
return 0;
}
STL应用没有什么模版,等这个明天再做一个专题专门总结一下学过的STL
栈和队列竟然也没有模版QAQ
接下来是图论:
图的遍历:
#include<cstdio>
#include<cstring>
using namespace std;
int n,m;
struct Edge{
int nxt,to;
}e[100001];
int a[1000001] = { };
int head[1000001],ecnt = 0;
void addEdge(int x,int y){
++ecnt;
e[ecnt].nxt = head[x];
e[ecnt].to = y;
head[x] = ecnt;
}
void dfs(int now,int p){
a[now] = p;
for(int i = head[now],v;~i; i = e[i].nxt){
if(a[v = e[i].to]) continue;
dfs(v,p);
}
}
int main(){
scanf("%d %d" ,&n,&m);
memset(head,-1,sizeof(head));
for(int i = 1;i <= m; i++){
int x,y;
scanf("%d %d" ,&x,&y);
addEdge(y,x);
}
for(int i = n;i; i--){
if(!a[i]) dfs(i,i);
}
for(int i = 1;i <= n; i++) printf("%d " ,a[i]);
return 0;
}
记录路径数量:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int mod=80112002;
int n,m,cnt=0;
struct edge
{
int to,nxt;
}edge[500005];
int head[500005],vis[500005],in[500005],out[500005],sum[500005];
void add(int x,int y)
{
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
head[x]=cnt;
}
int main()
{
cin>>n>>m;
int x,y;
for(int i=1;i<=m;i++)
{
cin>>x>>y;
add(x,y);
in[y]++;
out[x]++;
}
queue<int>q;
for(int i=1;i<=n;i++)
{
if(!in[i])
{
q.push(i);
sum[i]=1;
}
}
int ans=0;
while(!q.empty())
{
int v=q.front();
q.pop();
for(int i=head[v];i;i=edge[i].nxt)
{
int k=edge[i].to;
sum[k]=(sum[k]+sum[v])%mod;
in[k]--;
if(in[k]==0)
{
q.push(k);
}
}
}
for(int i=1;i<=n;i++)
{
if(out[i]==0)
{
ans=(ans+sum[i])%mod;
}
}
cout<<ans<<endl;
}
一个类似拓扑排序的应用(这道题原题是洛谷P1347)
#include<cstdio>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<string.h>
using namespace std;
int n,m;
struct Node{
int u;
int val;
Node(int u = 0 , int val = 0 ):u(u),val(val){}
};
vector<int> vec[50];
int ru[50];
int sum;
int ans;
int k;
set<int> s1;
void print(){
for(int i = 1 ; i <= n ; i++)printf("%c",(char)(i+'A'-1));
}
int have;
void topo(){
queue<Node> q;
for(int i = 0 ; i < 26; i++){
if(ru[i] == 0 && s1.count(i)){
q.push(Node(i,1));
sum++;
}
}
while(!q.empty()){
int u = q.front().u;
int val = q.front().val;
q.pop();
for(int i = 0; i < vec[u].size(); i++){
int v = vec[u][i];
ru[v]--;
if(ru[v]==0){
sum++;
q.push(Node(v,val+1));
ans=max(ans,val+1);
}
}
}
if(ans == n){
printf("Sorted sequence determined after %d relations: ",k);
print();
cout<<".";
exit(0);
}
if(sum != have){
printf("Inconsistency found after %d relations.",k);
exit(0);
}
}
int ru2[50];
int main(){
cin >> n >> m;
for(int i = 1 ; i <= m ; i++){
string s;
cin >> s;
k = i;
vec[s[0]-'A'].push_back(s[2]-'A');
s1.insert(s[0]-'A');
s1.insert(s[2]-'A');
have = s1.size();
ru2[s[2]-'A']++;
sum = 0;
ans = 0;
memcpy(ru,ru2,sizeof(ru2));
topo();
}
printf("Sorted sequence cannot be determined.");
return 0;
}
图的dfs和bfs:
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=1e5+5;
vector<int> graph[maxn];
int flag[maxn];
void dfs(int v)
{
flag[v]=true;
cout<<v<<" ";
for(int i=0;i<graph[v].size();i++)
{
if(!flag[graph[v][i]])
{
dfs(graph[v][i]);
}
}
}
void bfs(int v)
{
queue<int>t;
t.push(v);
flag[v]=true;
while(!t.empty())
{
int v1=t.front();
t.pop();
cout<<v1<<" ";
for(int i=0;i<graph[v1].size();i++)
{
if(!flag[graph[v1][i]])
{
t.push(graph[v1][i]);
flag[graph[v1][i]]=true;
}
}
}
}
int main()
{
int n,m,v1,v2;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>v1>>v2;
graph[v1].push_back(v2);
}
for(int i=1;i<=n;i++)
{
sort(graph[i].begin(),graph[i].end());
}
memset(flag,false,sizeof(flag));
dfs(1);
memset(flag,false,sizeof(flag));
cout<<endl;
bfs(1);
return 0;
}
单源最短路DJ哥斯拉优化版:
#include<cstring>
#include<cstdio>
#include<queue>
#include<iostream>
#include<utility>
#include<algorithm>
using namespace std;
typedef pair<int,int> pr;
struct Edge{
int nxt,to,w;
}e[300001];
struct cmp
{
bool operator()(const pr p1,const pr p2)
{
return p1.second < p2.second;
}
};
int n,m,s;
int head[300001];
int ecnt = 0;
int dis[300001] = { };
priority_queue<pr, vector<pr>, greater<pr> > q;
void addEdge(int x,int y,int w){
++ecnt;
e[ecnt].nxt = head[x];
e[ecnt].w = w;
e[ecnt].to = y;
head[x] = ecnt;
}
int vis[300001] = { };
void dijkstra()
{
memset(dis, 0x3f,sizeof(dis));
dis[1] = 0;
q.push(make_pair(0, s));
while(!q.empty())
{
int now = q.top().second; q.pop();
if(vis[now]) continue;
vis[now] = 1;
for(int i = head[now]; ~i; i = e[i].nxt)
{
int v = e[i].to;
if(dis[v] > dis[now] + e[i].w)
{
dis[v] = dis[now] + e[i].w;
q.push(make_pair(dis[v], v));
}
}
}
}
int main(){
scanf("%d %d %d" ,&n,&m,&s);
memset(head,-1,sizeof(head));
for(int i = 1;i <= m; i++){
int a,b,c;
scanf("%d %d %d" ,&a,&b,&c);
addEdge(a,b,c);
}
dijkstra();
for(int i = 1;i <= n; i++){
printf("%d " ,dis[i]);
}
return 0;
}
DJ哥斯拉优化版最短路计数:
#include<cstring>
#include<cstdio>
#include<queue>
#include<iostream>
#include<utility>
#include<algorithm>
using namespace std;
int dis[3000001] = { };
struct Edge{
int nxt,to,w;
}e[1000001];
int head[100001];
int ecnt = 0;
typedef pair<int,int> pr;
struct cmp
{
bool operator()(const pr p1,const pr p2)
{
return p1.second < p2.second;
}
};
void addEdge(int x,int y){
++ecnt;
e[ecnt].nxt = head[x];
e[ecnt].w = 1;
e[ecnt].to = y;
head[x] = ecnt;
}
int n,m;
int vis[3000001] = { };
int s = 1;
int ans[1000001] = { };
priority_queue<pr, vector<pr>, greater<pr> > q;
void dijkstra()
{
memset(dis, 0x3f,sizeof(dis));
dis[1] = 0;
ans[1] = 1;
q.push(make_pair(0, s));
while(!q.empty())
{
int now = q.top().second;
int d = q.top().first;
q.pop();
//if(vis[now]) continue;
if(d != dis[now]) continue;
//vis[now] = 1;
for(int i = head[now]; ~i; i = e[i].nxt)
{
int v = e[i].to;
if(d + e[i].w == dis[v]){
ans[v] = (ans[now] + ans[v]) % 100003;
}
if(dis[v] > dis[now] + e[i].w)
{
dis[v] = dis[now] + e[i].w;
ans[v] = ans[now];
q.push(make_pair(dis[v], v));
}
}
}
}
int main(){
scanf("%d %d" ,&n,&m);
memset(head,-1,sizeof(head));
for(int i = 1;i <= m; i++){
int a,b;
scanf("%d %d" ,&a,&b);
if(a == b) continue;
addEdge(a,b);
addEdge(b,a);
}
dijkstra();
for(int i = 1;i <= n; i++){
printf("%d\n" ,ans[i]);
}
return 0;
}
分层图最短路(这个我一直理解的不好,有空要多看看,然后分层图最短路我在当日总结里提到过,到时候回去翻一下):
洛谷原题 P1948:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Edge{
int nxt,to,w;
}e[20005];
int n,p,k,ecnt = 0;
int head[1005],dis[1005],q[1005];
bool jd[1005];
void addEdge(int x,int y,int w){
++ecnt;
e[ecnt].nxt = head[x];
e[ecnt].w = w;
e[ecnt].to = y;
head[x] = ecnt;
}
bool solve(int x){
memset(dis,0x3f,sizeof(dis));
int t = 0,w = 1,i,now,s;
dis[1] = 0;
q[t] = 1;
jd[1] = 1;
while(t != w){
now = q[t];
t++;
if(t == 1001) t = 0;
i = head[now];
while(i){
if(e[i].w > x) s = dis[now] + 1;
else s = dis[now];
if(s < dis[e[i].to]){
dis[e[i].to] = s;
if(!jd[e[i].to]){
q[w++] = e[i].to;
jd[e[i].to] = 1;
if(w == 1001) w = 0;
}
}
i = e[i].nxt;
}
jd[now] = 0;
}
if(dis[n] <= k) return 1;
return 0;
}
int main(){
scanf("%d %d %d" ,&n,&p,&k);
int a,b,c;
int le = 0,ri = 1000000;
for(int i = 1;i <= p; i++){
scanf("%d %d %d" ,&a,&b,&c);
addEdge(a,b,c);
addEdge(b,a,c);
}
int ans = -1;
while(le <= ri){
int mid = (le + ri) >> 1;
if(solve(mid)){
ri = mid - 1;
ans = mid;
}
else{
le = mid + 1;
}
}
printf("%d" ,ans);
return 0;
}
判负环:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
struct Edge{
int nxt,to,w;
}e[30001];
int head[30001];
int ecnt = -1;
int n,m;
void addEdge(int x,int y,int w){
++ecnt;
e[ecnt].nxt = head[x];
e[ecnt].to = y;
e[ecnt].w = w;
head[x] = ecnt;
}
int cnt[30001] = { };
int dis[10001] = { };
int vis[10001] = { };
int flag = 0;
void spfa()
{
queue<int>q;
memset(dis, 0x3f,sizeof(dis));
memset(cnt, 0,sizeof(cnt));
memset(vis, 0,sizeof(vis));
dis[1] = 0;
q.push(1);
vis[1]=1;
while(!q.empty())
{
int now = q.front(); q.pop();
vis[now] = 0;
for(int i = head[now]; ~i; i = e[i].nxt)
{
int v = e[i].to;
if(dis[v] > dis[now] + e[i].w)
{
dis[v] = dis[now] + e[i].w;
cnt[v]=cnt[now]+1;
if(cnt[v] >= n){
printf("YES\n");
return;
}
if(!vis[v]) {
q.push(v);
vis[v] = 1;
}
}
}
}
printf("NO\n");
}
int k;
int main(){
scanf("%d" ,&k);
for(int j = 1;j <= k; j++){
memset(head,-1,sizeof(head));
scanf("%d %d" ,&n,&m);
ecnt=-1;
for(int i = 1;i <= m; i++){
int a,b,c;
scanf("%d %d %d" ,&a,&b,&c);
addEdge(a,b,c);
if(c>=0) addEdge(b,a,c);
}
spfa();
}
}
树
LCA(最近公共祖先):
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 5e5 + 5;
int n, m, s;
struct Edge
{
int nxt, to;
}e[maxn << 1];
int head[maxn], ecnt = -1;
void addEdge(int x, int y)
{
e[++ecnt] = (Edge){head[x], y};
head[x] = ecnt;
}
int dep[maxn], Dfs[2 * maxn], fir[maxn];
int cnt = 0;
void dfs(int u, int _f)
{
Dfs[++cnt] = u; fir[u] = cnt;
for(int i = head[u]; ~i; i = e[i].nxt)
{
int v = e[i].to;
if(v == _f) continue;
dep[v] = dep[u] + 1;
dfs(v, u);
Dfs[++cnt] = u;
}
}
int que[maxn << 1];
struct Node {int Min, pos;}dp[2 * maxn][25];
void init()
{
for(int i = 1; i <= cnt; ++i) dp[i][0] = (Node){dep[Dfs[i]], Dfs[i]};
for(int j = 1; (1 << j) <= cnt; ++j)
for(int i = 1; i + (1 << j) - 1 <= cnt; ++i)
{
if(dp[i][j - 1].Min < dp[i + (1 << (j - 1))][j - 1].Min) dp[i][j] = dp[i][j - 1];
else dp[i][j] = dp[i + (1 << (j - 1))][j - 1];
}
for(int i = 2; i <= cnt; ++i) que[i] = que[i >> 1] + 1;
}
int lca(int x, int y)
{
int L = fir[x], R = fir[y];
if(R < L) swap(L, R);
int k = que[R - L + 1];
if(dp[L][k].Min < dp[R - (1 << k) + 1][k].Min) return dp[L][k].pos;
else return dp[R - (1 << k) + 1][k].pos;
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d%d", &n, &m, &s);
for(int i = 1; i < n; ++i)
{
int x, y; scanf("%d%d", &x, &y);
addEdge(x, y);
addEdge(y, x);
}
dep[1] = 1;
dfs(s, 0);
init();
for(int i = 1; i <= m; ++i)
{
int x, y; scanf("%d%d", &x, &y);
printf("%d\n", lca(x, y));
}
return 0;
}
树状数组:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
int n,m,tree[2000010];
int lowbit(int k)
{
return k & -k;
}
void add(int x,int k)
{
while(x<=n)
{
tree[x]+=k;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans=0;
while(x!=0)
{
ans+=tree[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
scanf("%d %d" ,&n,&m);
for(int i=1;i<=n;i++)
{
int a;
scanf("%d",&a);
add(i,a);
}
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a==1)
add(b,c); //将第b个数加上c
if(a==2)
printf("%d\n" ,sum(c)-sum(b-1)); //输出区间[b,c]内的和
}
return 0;
}
并查集:
#include<cstdio>
using namespace std;
int p[100001] = { };
int n,m;
int Find(int x)
{
return x == p[x] ? x : p[x] = Find(p[x]);
}
void merge(int x, int y)
{
int px = Find(x), py = Find(y);
if(px == py) return;
p[px] = py;
}
int main(){
scanf("%d %d" ,&n,&m);
for(int i = 1;i <= n; i++){
p[i] = i;
}
for(int i = 1;i <= m; i++){
int z;
scanf("%d" ,&z);
if(z == 1){
int y,x;
scanf("%d %d" ,&x,&y);
merge(x,y);//将x,y合并
}
if(z == 2){
int x,y;
scanf("%d %d" ,&x,&y);
if(Find(x) == Find(y)) printf("Y\n"); //看x和y是否在一个集合中
else printf("N\n");
}
}
return 0;
}