ll exgcd(ll a,ll b,ll &x,ll &y)
{
if (!b)
{
x = 1,y = 0;
return a;
}
int r = exgcd(b,a%b,x,y);
int tmp = y;
y = x - (a / b) * y;
x = tmp;
return r;
}
以hduoj6470为例, f n = f n − 1 + 2 f n − 2 + n 3 fn = f_{n-1} + 2f_{n-2} + n^3 fn=fn−1+2fn−2+n3
#include
using namespace std;
#define ll long long
const ll mod = 123456789;
const int N = 6;
struct Matrix
{
int n;
ll d[6][6];
void init(int n)
{
this -> n = n;
memset(d,0,sizeof(d));
}
Matrix operator *(Matrix &b)
{
Matrix ans;
ans.init(n);
for (int i = 0;i < n;i ++)
for (int j = 0;j < n;j ++)
for (int k = 0;k < n;k ++)
ans.d[i][j]=(ans.d[i][j]+d[i][k]*b.d[k][j])%mod;
return ans;
}
};
ll a[N][N] = {
{1,1,0,0,0,0},
{2,0,0,0,0,0},
{1,0,1,0,0,0},
{3,0,3,1,0,0},
{3,0,3,2,1,0},
{1,0,1,1,1,1}
};
ll b[6] = {2,1,8,4,2,1};
Matrix quick(Matrix a,ll b)
{
Matrix res;
res.init(a.n);
for (int i = 0;i < res.n;i ++)
res.d[i][i] = 1;
while (b)
{
if (b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
int main()
{
ll t,n;
scanf("%lld",&t);
while (t --)
{
scanf("%lld",&n);
if (n < 2)
{
printf("%lld\n",n);
continue;
}
Matrix x,ans;
x.init(6),ans.init(6);
for (int i = 0;i < N;i ++)
for (int j = 0;j < N;j ++)
x.d[i][j] = a[i][j];
for (int i = 0;i<N;i++) ans.d[0][i]=b[i];
x = quick(x,n - 1);
ans = ans * x;
printf("%lld\n",ans.d[0][1]);
}
return 0;
}
ll ksc(ll a,ll b,ll p)
{
return (a*b-(ll)((long double)a/p*b)*p+p)%p;
}
ll prime[5] = {2, 5, 3, 233, 331};
ll qpow(ll a,ll b,ll p)
{
ll ans = 1;
while (b)
{
if (b & 1) ans = ksc(ans,a,p);
b >>= 1;
a = ksc(a,a,p);
}
return ans;
}
bool Miller_Rabin(ll p)
{
if(p < 2) return 0;
if(p != 2 && p % 2 == 0) return 0;
ll s = p - 1;
while(! (s & 1)) s >>= 1;
for(int i = 0; i < 3; ++i)
{
if(p == prime[i]) return 1;
ll t = s, m = qpow(prime[i], s, p);
while(t != p - 1 && m != 1 && m != p - 1)
{
m = ksc(m, m, p);
t <<= 1;
}
if(m != p - 1 && !(t & 1)) return 0;
}
return 1;
}
读入输出
inline __int128 read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline void print(__int128 x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
const int maxn = (int)5e2 + 10;
int G[maxn][maxn];
int vis[maxn];
int n,m;
void toposort()
{
for (int i = 1;i <= n;i ++)
{
for (int j = 1;j <= n;j ++)
{
if (!vis[j])
{
printf("%d",j);
vis[j]--;
if (i != n) putchar(' ');
else putchar('\n');
for (int k = 1;k <= n;k ++)
{
if (G[j][k]) vis[k]--;
}
break;
}
}
}
}
两次bfs,一次找底部节点,一次找直径,以poj2631为例
#include
#include
#include
#include
#include
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
const int maxn = (int)1e4 + 10;
vector<pair<int,int> > G[maxn];
int dis[maxn],ans;
bool vis[maxn];
int bfs(int x)
{
mem(dis);
mem(vis);
queue<int> q;
q.push(x);
int p = 0;
vis[x] = 1,dis[x] = 0;
while (!q.empty())
{
int t = q.front();
q.pop();
if (dis[t] > ans)
{
ans = dis[t];
p = t;
}
pair<int,int> r;
for (int i = 0;i < G[t].size();i ++)
{
r = G[t][i];
if (!vis[r.first])
{
vis[r.first] = 1;
dis[r.first] = dis[t] + r.second;
q.push(r.first);
}
}
}
return p;
}
int main()
{
int x,y,z;
while (cin>>x>>y>>z)
{
G[x].push_back(make_pair(y,z));
G[y].push_back(make_pair(x,z));
}
int point = bfs(1);
ans = 0;
bfs(point);
cout<<ans<<endl;
return 0;
}
const int maxn = (int)5e5 + 10;
int a[maxn],temp[maxn];
void merge_sort(int l,int r)
{
int mid = (l + r) >> 1;
if (l == r)
return ;
for (int i = l,j = mid + 1,pos = 0;i <= mid || j <= r;pos ++)
{
if (i > mid) temp[pos] = a[j ++];
else if (j > r) temp[pos] = a[i ++];
else if (a[i] <= a[j]) temp[pos] = a[i ++];
else
{
temp[pos] = a[j ++];
}
}
for (int i = 0;i <= r - l;i ++)
a[l + i] = temp[i];
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define inf 0x3f3f3f3f
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
char a[1005],b[1005],c[1005];
int dp[1005][1005];
int main()
{
scanf("%s %s",a,b);
int n = strlen(a),m = strlen(b);
dp[0][0] = 0;
for (int i = 0;i < n;i ++)
for (int j = 0;j < m;j ++)
{
if (a[i] == b[j])
dp[i + 1][j + 1] = dp[i][j] + 1;
else
dp[i + 1][j + 1] = max(dp[i][j + 1],dp[i + 1][j]);
}
int pos = 0;
while (dp[n][m])
{
if (dp[n - 1][m] == dp[n][m])
n --;
else if (dp[n][m - 1] == dp[n][m])
m --;
else
n--,m--,c[pos ++] = a[n];
}
while (pos) printf("%c",c[--pos]);
putchar('\n');
return 0;
}
链式前向星建图O(E * logN) 以HDUoj1874为例:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define inf 0x3f3f3f3f
#define mem(a) memset(a,-1,sizeof(a))
using namespace std;
typedef pair<int,int> par;
const int maxn = 110;
const int MAXN = 1010;
int n,m;
//链式前向星建图
struct Edge
{
int to,next,val;
Edge(){}
Edge(int _to,int _next,int _val)
{
to = _to,next = _next,val = _val;
}
}edge[MAXN << 1];
//初始化
int head[maxn],top;
void init(int n)
{
memset(head,-1,sizeof(int) * (n + 1));
top = 0;
}
//边
void add(int u,int v,int val)
{
edge[top] = Edge(v,head[u],val);
head[u] = top ++;
}
void getmap(int m)
{
int u,v,val;
while (m --)
{
scanf("%d %d %d",&u,&v,&val);
add(u,v,val);
add(v,u,val);//双向图
}
}
int dis[maxn];
void djk(int st,int end) //核心代码dijkstra算法
{
memset(dis,0x3f,sizeof(int) * (n + 1));
priority_queue<par,vector<par>,greater<par> > que;
dis[st] = 0,que.push(make_pair(0,st));
while (!que.empty())
{
par p = que.top();
que.pop();
int v = p.second;
if (dis[v] < p.first) continue;
for (int i = head[v]; ~i ;i = edge[i].next)
{
Edge e = edge[i];
if (dis[e.to] > dis[v] + e.val)
{
dis[e.to] = dis[v] + e.val;
que.push(make_pair(dis[e.to],e.to));
}
}
}
printf("%d\n",dis[end] == inf ? -1 : dis[end]);
}
int main()
{
int s,t;
while (~scanf("%d %d",&n,&m))
{
init(n);
getmap(m);
scanf("%d %d",&s,&t);
djk(s,t);
}
return 0;
}
O(n+m)
const int maxn = (int)1e6 + 10;
const int MAXN = (int)1e4 + 10;
int f[maxn];//母串
int s[MAXN];//子串
int nxt[MAXN];//预处理最长前后缀
int n,m;
void init()
{
int i = 1,j = 0;
nxt[0] = 0;
while (i < m)
{
if (s[i] == s[j])
nxt[i ++] = ++ j;
else if (!j)
i ++;
else
j = nxt[j - 1];
}
}
int kmp()
{
int i = 0,j = 0;
while (i < n && j < m)
{
if (f[i] == s[j])
{
i ++;
j ++;
}
else if (!j)
i ++;
else
j = nxt[j - 1];
}
if (j == m)
return i - m + 1;//返回第一次匹配的首字母位置
return -1;//无匹配
}
#define N 30100
//N为最大点数
#define M 150100
//M为最大边数
int n, m;//n m 为点数和边数
struct Edge{
int from, to, nex;
bool sign;//是否为桥
}edge[M<<1];
int head[N], edgenum;
void add(int u, int v){//边的起点和终点
Edge E={u, v, head[u], false};
edge[edgenum] = E;
head[u] = edgenum++;
}
int DFN[N], Low[N], Stack[N], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳)
int taj;//连通分支标号,从1开始
int Belong[N];//Belong[i] 表示i点属于的连通分支
bool Instack[N];
vector<int> bcc[N]; //标号从1开始
void tarjan(int u ,int fa){
DFN[u] = Low[u] = ++ Time ;
Stack[top ++ ] = u ;
Instack[u] = 1 ;
for (int i = head[u] ; ~i ; i = edge[i].nex ){
int v = edge[i].to ;
if(DFN[v] == -1)
{
tarjan(v , u) ;
Low[u] = min(Low[u] ,Low[v]) ;
if(DFN[u] < Low[v])
{
edge[i].sign = 1;//为割桥
}
}
else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ;
}
if(Low[u] == DFN[u]){
int now;
taj ++ ; bcc[taj].clear();
do{
now = Stack[-- top] ;
Instack[now] = 0 ;
Belong [now] = taj ;
bcc[taj].push_back(now);
}while(now != u) ;
}
}
void tarjan_init(int all){
memset(DFN, -1, sizeof(DFN));
memset(Instack, 0, sizeof(Instack));
top = Time = taj = 0;
for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!!
}
vector<int>G[N];
int du[N];
void shk(){
memset(du, 0, sizeof(du));
for(int i = 1; i <= taj; i++)G[i].clear();
for(int i = 0; i < edgenum; i++){
int u = Belong[edge[i].from], v = Belong[edge[i].to];
if(u!=v)G[u].push_back(v), du[v]++;
}
}
void init()
{
memset(head, -1, sizeof(head));
edgenum=0;
}
O(n*m2)
#define ll long long
using namespace std;
const ll inf = 34338315071127552;
int n,m,s,t;
struct Node{
ll v;
ll val;
ll next;
}node[20101];
int top=1,head[10101];//top必须从一个奇数开始,一般用-1但我不习惯,解释见下方
void init(int n)
{
memset(head,-1,sizeof(int)*(n+1));
top = 1;
}
inline void addedge(ll u,ll v,ll val){
node[++top].v=v;
node[top].val=val;
node[top].next=head[u];
head[u]=top;
}
inline int Read(){
int x=0;
char c=getchar();
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x;
}
ll inque[10101];//点是访问过里
struct Pre{
ll v;//该点的前一个点(从起点过来)
ll edge;//与该点相连的边(靠近起点的)
}pre[10101];
inline bool bfs(){
queue<ll>q;
memset(inque,0,sizeof(inque));
memset(pre,-1,sizeof(pre));
inque[s]=1;
q.push(s);
while(!q.empty()){
ll u=q.front();
q.pop();
for(int i=head[u];i;i=node[i].next){
ll d=node[i].v;
if(!inque[d]&&node[i].val){//node[i].val==0则已经该路径满了
pre[d].v=u;
pre[d].edge=i;
if(d==t)return 1;
inque[d]=1;
q.push(d);
}
}
}
return 0;
}//是否有增广路
ll EK(){
ll ans=0;
while(bfs()){
ll mi=inf;
for(int i=t;i!=s;i=pre[i].v){
mi=min(mi,node[pre[i].edge].val);//每次只能增加增广路上最小的边的权值
}
for(int i=t;i!=s;i=pre[i].v){
node[pre[i].edge].val-=mi;
node[pre[i].edge^1].val+=mi;
//反向的边的编号是正向边的编号^1
//这就是为什么top开始时必须是奇数
}
ans+=mi;
}
return ans;
}
O(n2*m)
#define ll long long
//Dinic网络最大流模板
const ll inf=1LL*1<<60;
const int maxn = 10101;
int dep[10101],head[10101],inque[10101];
int top=1;
ll maxflow=0;
int n,m,s,t;
struct Node{
int v;
ll val;
int next;
}node[200100];
void init()
{
memset(head,-1,sizeof(int)*(n+1));
top = 1;
}
inline void addedge(int u,int v,ll val){
node[++top].v=v;
node[top].val=val;
node[top].next=head[u];
head[u]=top;
}
int Read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0')c=getchar(),f=-1;
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x*f;
}
bool bfs(){
memset(dep,0x3f,sizeof(int)*(n+1));
memset(inque,0,sizeof(inque));
dep[s]=0;
queue<int>q;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
inque[u]=0;
for(int i=head[u];~i;i=node[i].next){
int d=node[i].v;
if(dep[d]>dep[u]+1&&node[i].val){
dep[d]=dep[u]+1;//注意与EK的区别
if(inque[d]==0){
q.push(d);
inque[d]=1;
}
}
}
}
if(dep[t]!=0x3f3f3f3f)return 1;
return 0;
}//给增广路上的点分层
ll dfs(int u,ll flow){
ll rlow=0;
if(u==t){
maxflow+=flow;//其实可以直接在这里累加最大流
return flow;
}
ll used=0;//该点已经使用的流量
for(int i=head[u];i;i=node[i].next){
int d=node[i].v;
if(node[i].val&&dep[d]==dep[u]+1){
if(rlow=dfs(d,min(flow-used,node[i].val))){
used+=rlow;//该点使用的流量增加
node[i].val-=rlow;
node[i^1].val+=rlow;
if(used==flow)break;//该点流量满了,没必要再找了
}
}
}
return used;//返回该点已使用流量
}//多路寻找增广路
ll Dinic(){
while(bfs()){
dfs(s,inf);
}
return maxflow;
}//Dinic寻找最大流
O(n+q)
#include
#define N 500050
struct hehe{
int next;
int to;
int lca;
};
hehe edge[N];//树的链表
hehe qedge[N];//需要查询LCA的两节点的链表
int n,m,p,x,y;
int num_edge,num_qedge,head[N],qhead[N];
int father[N];
int visit[N];//判断是否被找过
void add_edge(int from,int to){//建立树的链表
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
head[from]=num_edge;
}
void add_qedge(int from,int to){//建立需要查询LCA的两节点的链表
qedge[++num_qedge].next=qhead[from];
qedge[num_qedge].to=to;
qhead[from]=num_qedge;
}
int find(int z){//找爹函数
if(father[z]!=z)
father[z]=find(father[z]);
return father[z];
}
void dfs(int x){//把整棵树的一部分看作以节点x为根节点的小树
father[x]=x;//由于节点x被看作是根节点,所以把x的father设为它自己
visit[x]=1;//标记为已被搜索过
for(int k=head[x];k;k=edge[k].next)//遍历所有与x相连的节点
if(!visit[edge[k].to]){//若未被搜索
dfs(edge[k].to);//以该节点为根节点搞小树
father[edge[k].to]=x;//把x的孩子节点的father重新设为x
}
for(int k=qhead[x];k;k=qedge[k].next)//搜索包含节点x的所有询问
if(visit[qedge[k].to]){//如果另一节点已被搜索过
qedge[k].lca=find(qedge[k].to);//把另一节点的祖先设为这两个节点的最近公共祖先
if(k%2)//由于将每一组查询变为两组,所以2n-1和2n的结果是一样的
qedge[k+1].lca=qedge[k].lca;
else
qedge[k-1].lca=qedge[k].lca;
}
}
int main(){
scanf("%d%d%d",&n,&m,&p);//输入节点数,查询数和根节点
for(int i=1;i<n;++i){
scanf("%d%d",&x,&y);//输入每条边
add_edge(x,y);
add_edge(y,x);
}
for(int i=1;i<=m;++i){
scanf("%d%d",&x,&y);//输入每次查询,考虑(u,v)时若查找到u但v未被查找,所以将(u,v)(v,u)全部记录
add_qedge(x,y);
add_qedge(y,x);
}
dfs(p);//进入以p为根节点的树的深搜
for(int i=1;i<=m;i++)
printf("%d\n",qedge[i*2].lca);//两者结果一样,只输出一组即可
return 0;
}