1.转圈游戏
(circle.cpp/c/pas)
【问题描述】
n 个小伙伴(编号从 0 到 n-1)围坐一圈玩游戏。按照顺时针方向给 n 个位置编号,从
0 到 n-1。最初,第 0 号小伙伴在第 0 号位置,第 1 号小伙伴在第 1 号位置,……,依此类推。
游戏规则如下:每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,……,依此类推,第n − m号位置上的小伙伴走到第 0 号位置,第 n-m+1 号位置上的小伙伴走到第 1 号位置,……,第 n-1 号位置上的小伙伴顺时针走到第 m-1 号位置。
现在,一共进行了 10^k 轮,请问 x 号小伙伴最后走到了第几号位置。
【输入】
输入文件名为 circle.in。
输入共 1 行,包含 4 个整数 n、m、k、x,每两个整数之间用一个空格隔开。
【输出】
输出文件名为 circle.out。
输出共 1 行,包含 1 个整数,表示 10k 轮后 x 号小伙伴所在的位置编号。
【输入样例】
10 3 4 5
【输出样例】
5
【数据说明】
对于 30%的数据,0 ≤k<≤6;
对于 80%的数据,0 ≤k≤ 10^7;
对于 100%的数据,1 ≤n<≤1,000,000,0 ≤m≤n ,1 ≤ x ≤ n,0 ≤k≤ 10^9。
思路:用到快速幂优化,背诵内容
#include<cstdio>
typedef long long LL;
using namespace std;
int n,m,k,x;
LL fuc(int p,int k){
LL temp=p,s=1;
while(k!=0){
if(k&1) s=(s*(temp%n))%n;
temp=(temp*temp)%n;
k>>=1;
}
return s;
}
int main(){
// freopen("circle.in","r",stdin);
// freopen("circle.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&k,&x);
printf("%I64d",(m*fuc(10,k)+x)%n);
return 0;
}
//printf %I64d 去掉 LL去掉 则无错误
火柴排队
(match.cpp/c/pas)
【问题描述】
涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:Σni=(ai−bi)2,其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最
小交换次数对 99,999,997 取模的结果。
【输入】输入文件为 match.in。
共三行,第一行包含一个整数 n,表示每盒中火柴的数目。
第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
【输出】输出文件为 match.out。
输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。
【输入输出样例 1】
4 1
2 3 1 4
3 2 1 4
【输入输出样例说明】
最小距离是 0,最少需要交换 1 次,比如:交换第 1 列的前 2 根火柴或者交换第 2 列的前 2 根火柴。
【输入输出样例 2】
4 2
1 3 4 2
1 7 2 4
【输入输出样例说明】
最小距离是 10,最少需要交换 2 次,比如:交换第 1 列的中间 2 根火柴的位置,再交换第 2 列中后 2 根火柴的位置。
【数据范围】
对于 10%的数据, 1 ≤ n ≤10;
对于 30%的数据,1 ≤ n ≤ 100;
对于 60%的数据,1 ≤ n ≤ 1,000;
思路:a序列里第几大的要对上b序列里第几大的,可用结构体使a、b序列重新对齐
//逆序对 归并排序
//大对大,小对小
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[100010],b[100010],temp[100010],aa[100010],bb[100010];
void qs(int *x,int *y,int l,int r){
int i=l,j=r,m=x[(l+r)>>1];
while(i<=j){
while(x[i]<m)i++;
while(x[j]>m)j--;
if(i<=j){
swap(x[i],x[j]);
swap(y[i++],y[j--]);
}
}
if(i<r) qs(x,y,i,r);
if(j>l) qs(x,y,l,j);
}
long long merge(int *a,int l,int m,int r,int *b){
int i=l,k=l,j=m+1;
long long sum=0;
memcpy(b+l,a+l,sizeof(int)*(r-l+1));
while(i<=m&&j<=r){
if(b[i]<=b[j])
a[k++]=b[i++];
else{
a[k++]=b[j++];
sum+=(m-i+1);
sum%=99999997;
}
}
while(i<=m) a[k++]=b[i++];
while(j<=r) a[k++]=b[j++];
return sum;
}
long long merge_sort(int *a,int l,int r,int *b){
long long sum=0;
if(l<r){
int m=(l+r)>>1;
sum+=merge_sort(a,l,m,b);
sum+=merge_sort(a,m+1,r,b);
sum+=merge(a,l,m,r,b);
sum%=99999997;
}
return sum;
}
int main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
int n,i;
long long sum;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]),
aa[i]=i;
for(i=1;i<=n;i++)
scanf("%d",&b[i]),
bb[i]=i;
qs(a,aa,1,n);
qs(b,bb,1,n);
for(i=1;i<=n;i++)
b[aa[i]]=bb[i];
sum=merge_sort(b,1,n,temp);
printf("%lld",sum);
return 0;
}
或者
//树状数组
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int siz=100010,mod=99999997;
int n,ans;
int an[siz],c[siz];
struct node{int v,i;} a[siz],b[siz];
bool cmp(const node &c,const node &d){return c.v<d.v;}
int lowbit(int x){return x&(-x);}
void add(int x,int y){for(;x<=n;x+=lowbit(x)) c[x]+=y;}
//加上去
int get(int x){int res=0;for(;x;x-=lowbit(x)) res+=c[x];return res;}
//求前缀和
int main(){
ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].v),a[i].i=i;
for(int i=1;i<=n;i++)
scanf("%d",&b[i].v),b[i].i=i;
sort(a+1,a+1+n,cmp);sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++)
an[a[i].i]=b[i].i;
//把b里的顺序按照a里的改了 a[i]第几个 a[i].i这个位置的数的大小排位
for(int i=n;i>=1;i--){
ans+=get(an[i]-1);
ans%=mod;
add(an[i],1);
}
cout<<ans<<endl;
return 0;
}
货车运输
(truck.cpp/c/pas)
【问题描述】
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
【输入】输入文件名为 truck.in。
输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道
路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。
【输出】输出文件名为 truck.out。
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。
【输入样例】
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
【输出样例】
3
-1
3
【数据说明】
对于 30%的数据,0 ≤n≤1,000,0 ≤m≤ 10,000,0≤q≤1,000;对于 60%的数据,0 ≤n≤1,000,0 ≤m≤50,000,0 ≤q≤ 1,000;
对于 100%的数据,0 ≤n≤10,000,0 ≤m≤50,000,0 ≤q≤30,000,0 ≤ z ≤ 100,000。
思路:最大生成树+LCA.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
vector <int> ans1[10010];
int m,n,q;
int father[10010],s[30010],t[30010];
int ans[30010];
bool vist[30010];
struct node{
int x,y,z;
}a[51000];
int getfa(int x)//找爹
{
if(father[x]==x) return x;
return father[x]=getfa(father[x]);
}
bool jianb(int x,int y)//建边
{
int a=getfa(x),b=getfa(y);
if(a!=b)
{
father[b]=a;
return false;
}
return true;
}
int cmp(node xx,node yy)//根据边权的大小排序
{
return xx.z>yy.z;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
father[i]=i;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
sort(a+1,a+m+1,cmp);
scanf("%d",&q);
for(int i=1;i<=q;i++)
scanf("%d%d",&s[i],&t[i]);
for(int i=1;i<=m;i++)
{
if(getfa(a[i].x)!=getfa(a[i].y))
jianb(a[i].x,a[i].y);
if(i==m || i%100==0)
{
for(int j=1;j<=q;j++)
if(vist[j]==0 && getfa(s[j])==getfa(t[j]))
vist[j]=1,
ans1[(i-1)/100].push_back(j);
}
}
for(int i=1;i<=n;i++)
father[i]=i;
memset(ans,-1,sizeof(ans));//如果无法求解,则输出-1
for(int i=1;i<=m;i++)
{
if(getfa(a[i].x)!=getfa(a[i].y))//若无连接,则连起来
jianb(a[i].x,a[i].y);
int num=(i-1)/100;
for(int j=0;j<ans1[num].size();j++)
{
if(ans[ans1[num][j]]==-1&&getfa(s[ans1[num][j]])==getfa(t[ans1[num][j]]))
ans[ans1[num][j]]=a[i].z;
}
}
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
return 0;
}
这里有大神的详注