【模板】矩阵快速幂 2714
性感手枪 4145
简单题 2723
货车运输 1807
【模板】树状数组 区间修改区间求和 1685
【模板】矩阵快速幂 2714
矩阵乘法
快速幂
一个 n * p 的矩阵与一个 p * m 的矩阵,相乘得到一个 n * m 的矩阵
题解
f(1)=1;f(2)=1;f(n)=A f(n-1)+B f(n-2);
所以
矩阵乘法公式:A * B->C
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=30013;
struct Array{
ll matrix[2][2];
}t,ans,temp;
ll a,b,k;
Array mul(Array a,Array b){
Array res;
memset(res.matrix,0,sizeof(res.matrix));
for(ll i=0;i<2;i++)
for(ll j=0;j<2;j++)
for(ll k=0;k<2;k++){
res.matrix[i][j]+=a.matrix[i][k]*b.matrix[k][j]%mod;
res.matrix[i][j]%=mod;
}
return res;
}
Array maxtrix_ksm(Array a,ll b){
Array res,temp;
memset(res.matrix,0,sizeof(res.matrix));
for(ll i=0;i<2;i++)
res.matrix[i][i]=1;
temp=a;
while(b){
if(b&1)res=mul(res,temp);
temp=mul(temp,temp);
b>>=1;
}
return res;
}
int main(){
memset(t.matrix,0,sizeof(t.matrix));
cin>>a>>b;
ans.matrix[0][0]=ans.matrix[0][1]=1;
t.matrix[0][0]=a;t.matrix[0][1]=1;
t.matrix[1][0]=b;t.matrix[1][1]=0;
cin>>k;
if(k==1||k==2){
cout<<ans.matrix[0][k-1];
return 0;
}
temp=maxtrix_ksm(t,k-2);
ans=mul(ans,temp);
cout<<ans.matrix[0][0];
return 0;
}
性感手枪 4145
%%%
DFS
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
bool a[1510][1510];
int vis[1510][1510][3];//x坐标 y坐标 是否访问
int n,m,sx,sy,ans,t;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
void dfs(int x,int y,int px,int py){//小矩阵中的坐标 大矩阵中的坐标
if(ans)return;
if(vis[px][py][2]&&(vis[px][py][0]!=x||vis[px][py][1]!=y)){
ans=1;return;//再次访问某个节点,但已是另一个复制的周边矩阵里的
}
if(vis[px][py][2]&&vis[px][py][0]==x&&vis[px][py][1]==y)return;
vis[px][py][0]=x;vis[px][py][1]=y;vis[px][py][2]=1;
int xx,yy;
for (int i=0;i<4;i++){
xx=(px+dx[i]+n)%n;yy=(py+dy[i]+m)%m;
if (a[xx][yy])dfs(x+dx[i],y+dy[i],xx,yy);
}
}
char c;
int main(){
t=read();
while(t--){
memset(a,false,sizeof(a));
memset(vis,false,sizeof(vis));
ans=0;
n=read();m=read();
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
c=getchar();
while(c!='S'&&c!='.'&&c!='#')c=getchar();
if(c=='S'){
sx=i;sy=j;a[i][j]=1;
}
if(c=='.')a[i][j]=1;
if(c=='#')a[i][j]=0;
}
dfs(sx,sy,sx,sy);
if(ans)printf("Yes\n");
else printf("No\n");
}
return 0;
}
简单题 2723
kruskal
最小瓶颈路
倍增
最小瓶颈路,是指两点之间所有路径中最大的边最小的路径(路径由边组成)
先构造一棵kruskal最小生成树,那么最小瓶颈路必然在这棵生成树上面。
对于每一对点,我们可以像找LCA一样找到最大值。
#include<bits/stdc++.h>
using namespace std;
struct edge{
int u,v,w,nxt;
}e[100010],a[100010];
int first[10010],cnt=0;
inline void add(int u,int v,int w){
a[++cnt].v=v;a[cnt].w=w;
a[cnt].nxt=first[u];first[u]=cnt;
}
inline int Sort_5(edge x,edge y){
return x.w<y.w;
}
int n,m,fa[10010][22],q;
inline int find(int x){
if(x==fa[x][0])return x;
return fa[x][0]=find(fa[x][0]);
}
int dep[10010],mx[10010][22];
void prework(int x,int f){
fa[x][0]=f;
dep[x]=dep[f]+1;
for(int i=1;(1<<i)<=dep[x];i++){
fa[x][i]=fa[fa[x][i-1]][i-1];
mx[x][i]=max(mx[fa[x][i-1]][i-1],mx[x][i-1]);
}
for(int i=first[x];i;i=a[i].nxt){
int v=a[i].v;
if(v==f)continue;
mx[v][0]=a[i].w;
prework(v,x);
}
}
int ask(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int t=dep[u]-dep[v],ans=0;
for(int i=0;i<=21;i++)
if(t&(1<<i)){
ans=max(ans,mx[u][i]);
u=fa[u][i];
}
if(u==v)return ans;
for(int i=21;i>=0;i--)
if(fa[u][i]!=fa[v][i]){
ans=max(ans,max(mx[u][i],mx[v][i]));
u=fa[u][i];v=fa[v][i];
}
return max(ans,max(mx[u][0],mx[v][0]));
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)fa[i][0]=i;
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
sort(e+1,e+m+1,Sort_5);
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v;
int fu=find(u),fv=find(v);
if(fu==fv)continue;
fa[fu][0]=fv;
add(fu,fv,e[i].w);add(fv,fu,e[i].w);
}
memset(fa,0,sizeof(fa));
prework(1,0);
scanf("%d",&q);
while(q--){
int u,v;
scanf("%d%d",&u,&v);
printf("%d\n",ask(u,v));
}
return 0;
}
货车运输 1807
kruskal
最小瓶颈路
倍增
和上面一样,只不过是最大瓶颈路。
#include<bits/stdc++.h>
using namespace std;
struct edge{
int u,v,w,nxt;
}e[100010],a[100010];
int first[10010],cnt=0;
inline void add(int u,int v,int w){
a[++cnt].v=v;a[cnt].w=w;
a[cnt].nxt=first[u];first[u]=cnt;
}
inline int Sort_5(edge x,edge y){
return x.w>y.w;
}
int n,m,fa[10010][22],q,anc[10010];
inline int find(int x){
if(x==anc[x])return x;
return anc[x]=find(anc[x]);
}
int dep[10010],mn[10010][22];
void prework(int x,int f){
fa[x][0]=f;
dep[x]=dep[f]+1;
for(int i=1;(1<<i)<=dep[x];i++){
fa[x][i]=fa[fa[x][i-1]][i-1];
mn[x][i]=min(mn[fa[x][i-1]][i-1],mn[x][i-1]);
}
for(int i=first[x];i;i=a[i].nxt){
int v=a[i].v;
if(v==f)continue;
mn[v][0]=a[i].w;
prework(v,x);
}
}
int ask(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int t=dep[u]-dep[v],ans=2000000000;
for(int i=0;i<=21;i++)
if(t&(1<<i)){
ans=min(ans,mn[u][i]);
u=fa[u][i];
}
if(u==v)return ans;
for(int i=21;i>=0;i--)
if(fa[u][i]!=fa[v][i]){
ans=min(ans,min(mn[u][i],mn[v][i]));
u=fa[u][i];v=fa[v][i];
}
return min(ans,min(mn[u][0],mn[v][0]));
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)anc[i]=i;
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
sort(e+1,e+m+1,Sort_5);
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v;
int fu=find(u),fv=find(v);
if(fu==fv)continue;
anc[fu]=fv;
add(fu,fv,e[i].w);add(fv,fu,e[i].w);
}
memset(mn,0x3f,sizeof(mn));
for(int i=1;i<=n;i++)
if(!dep[i]){//可能不连通
dep[i]=1;
prework(i,0);
}
scanf("%d",&q);
while(q--){
int u,v;
scanf("%d%d",&u,&v);
if(find(u)!=find(v)){
printf("-1\n");
continue;
}
printf("%d\n",ask(u,v));
}
return 0;
}
【模板】树状数组 区间修改区间求和 1685
树状数组
xxxly%%%
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
struct BIT{
ll t[400010]={0};
void add(int x,ll v){
for(;x<=n;x+=x&-x)t[x]+=v;
}
ll ask(int x){
ll ans=0;
for(;x;x-=x&-x)ans+=t[x];
return ans;
}
}c1,c2;
ll a[100010];
ll ans;
int main(){
// freopen("1.in","r",stdin);
scanf("%d%d",&n,&m);
int e,f,c;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
c1.add(i,a[i]-a[i-1]);
c2.add(i,(i-1)*1ll*(a[i]-a[i-1]));
}
while(m--){
scanf("%d%d%d",&c,&e,&f);
if(c==1){//区间加
scanf("%d",&c);
c1.add(e,c);c1.add(f+1,-c);
c2.add(e,(e-1)*c);c2.add(f+1,-f*c);
}
else{//区间求和
ans=f*c1.ask(f)-c2.ask(f);
ans-=(e-1)*c1.ask(e-1)-c2.ask(e-1);
printf("%lld\n",ans);
}
}
return 0;
}