T1转圈游戏
思路:
手玩一下数据可以发现:
x小朋友最终到达的位置为:
(x+(m*10^k)%n)%n
可以发现:
10^k可以用快速幂求得,
这题其实是快速幂模板!
上代码:
#include <cstdio> using namespace std; int n,m,k,x; int qpow(int x,int k) { int a=1; for(; k; k>>=1,x=x*x%n) if(k&1) a=a*x%n; return a; } int main() { scanf("%d%d%d%d",&n,&m,&k,&x); printf("%d",(x+m*qpow(10,k)%n)%n); return 0; }
T2火柴排队
思路:
距离为∑(ai-bi)^2,所以需要使得ai-bi尽可能的小
所以首先要明白,将两盒火柴的高度排序后,序号相同的火柴对应的位置应该相同。
即如果第一盒火柴中在第i个位置上放第j矮的火柴,那么第二盒火柴在第i个位置上也应该放第j矮的火柴。
否则除此之外随意互换,每次互换都只能使两盒火柴之间距离变大。
所以第一步就是给每根火柴编号,接着我们会得到两个序号序列。
我们现在要做的就变成了用最少的相邻交换,使得序号序列a(第一盒火柴)变成序号序列b(第二盒火柴)
即:
将b数组编号,第i个位置上的数对应i(得出映射map),
然后把a数组的每个编号a[i],变成map[a[i]](map为它的映射)
这样a[i]就表示a数组第i个数该换到哪个位置上
然后再把a数组求逆序对就可以了(可以采用树状数组求逆序对或者归并排序求逆序对等)
上代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define lb(x) (x&(-x)) using namespace std; const int N = 100009; const int Mod = 99999997; int n,ans; int c[N],e[N]; struct node { int w,id; bool operator < (const node &qwq) const { return w < qwq.w; } } a[N],b[N]; void add (int x,int j) { while(x<=n) { e[x]+=j; e[x]%=Mod; x+=lb(x); } } int sum(int x) { int ret=0; while(x) { ret+=e[x]; ret%=Mod; x-=lb(x); } return ret; } int main() { scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d",&a[i].w); a[i].id=i; } for(int i=1; i<=n; i++) { scanf("%d",&b[i].w); b[i].id=i; } sort(a+1,a+1+n); sort(b+1,b+1+n); for(int i=1; i<=n; i++) c[a[i].id]=b[i].id; for(int i=1; i<=n; i++) { add(c[i],1); ans+=i-sum(c[i]); ans%=Mod; } printf("%d",ans); return 0; }
T3货车运输
思路:
这个问题叫做『最大瓶颈路径』————>最大瓶颈路径一定存在于最大生成树中
反证法:如果最大瓶颈路径不存在与最大生成树中,那么这些不在最大生成树中的边会和最大生成树形成环。
若我们删掉环上最小的边,保留这一条边,会得到一棵新的更大的生成树,这与原来那棵树是最大生成树矛盾了。所以最大瓶颈路径一定存在于最大生成树中得证。
所以这个题目首先要求最大生成树。
而对于每一个询问,实际上是求树上的两点,路径包括的所有边的权值最小值。
故正解为倍增+LCA
坑点:
最短路不一定在最小生成树上(如一个环的情况)
上代码:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define Min(a,b) ((a)<(b)?a:b) #define INF (int)1e9 using namespace std; const int N = 10010; const int M = 50050; const int re = 20; struct Solve { int u,v,w; bool operator < (const Solve &qwq) const { return w > qwq.w; } } t[M]; struct Better { int next,to,w; } e[N<<1]; int n,m,q; int vis[N],dad[N],dep[N],jumps[N][re+1],j[N][re+1]; void Swap(int &a,int &b) { int tmp=a; a=b,b=tmp; } int top,head[N]; void add(int u,int v,int w) { top++; e[top].next=head[u]; head[u]=top; e[top].to=v; e[top].w=w; } void dfs(int u) { vis[u]=1; for(int i=1; i<=re; ++i) jumps[u][i]=jumps[jumps[u][i-1]][i-1], j[u][i]=Min(j[u][i-1],j[jumps[u][i-1]][i-1]); for(int i=head[u]; i; i=e[i].next) { int v=e[i].to; if(!vis[v]) { dep[v]=dep[u]+1; jumps[v][0]=u; j[v][0]=e[i].w; dfs(v); } } } int getdad(int x) { return x == dad[x] ? x : dad[x]=getdad(dad[x]); } int getlca(int a,int b) { if(dep[a]<dep[b]) Swap(a,b); for(int i=re; i>=0; --i) if(dep[jumps[a][i]]>=dep[b]) a=jumps[a][i]; if(a==b) return a; for(int i=re; i>=0; --i) if(jumps[a][i]!=jumps[b][i]) a=jumps[a][i],b=jumps[b][i]; return jumps[a][0]; } int ask(int x,int f) { int ret=INF; int deep=dep[x]-dep[f]; for(int i=0; i<=re; ++i) if(deep & (1<<i))///若能跳 ret=Min(ret,j[x][i]),x=jumps[x][i]; return ret; } int main() { memset(j,0x3f,sizeof(j)); scanf("%d%d",&n,&m); for(int i=1; i<=m; ++i) scanf("%d%d%d",&t[i].u,&t[i].v,&t[i].w); sort(t+1,t+1+m); for(int i=1; i<=n; ++i) dad[i]=i; for(int i=1; i<=m; ++i) { int die1=getdad(t[i].u); int die2=getdad(t[i].v); if(die1!=die2) { dad[die1]=die2; add(t[i].u,t[i].v,t[i].w); add(t[i].v,t[i].u,t[i].w); } } for(int i=1; i<=n; ++i) if(!vis[i]) dfs(i); scanf("%d",&q); for(int i=1,x,y; i<=q; ++i) { scanf("%d%d",&x,&y); if(getdad(x)!=getdad(y)) { printf("-1 "); continue; } int lca=getlca(x,y); printf("%d ",Min(ask(x,lca),ask(y,lca))); } return 0; }