7.11 noip2013提高组复赛day1

第一题:转圈游戏

一开始还没想到用快速幂(二分)的方法。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n;
long long dfn(int k){
if(k==1)return 10%n;
long long x=dfn(k>>1);
if(k&1){
return (x%n)*((x%n)*10)%n;//用x=dfn(k>>1),避免运算两次,优化。
}else return (x%n)*(x%n)%n;
}
main()
{
freopen("circle.in","r",stdin);
freopen("circle.out","w",stdout);
int m,k,x;long long sum;
scanf("%d%d%d%d",&n,&m,&k,&x);
sum=dfn(k);
sum=((sum*m)%n+x)%n;
printf("%I64d",sum);
}

第二题:火柴排队

首先判断出需要排序,排序后求逆序对,这里只用求一列数据就行。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
struct node{
int num;int sum;
};node a[100005],b[100005];
int cmp(const node &x,const node &y){
return x.sum<y.sum;
}
int tot,T[100005],n,c[100005];

/*
void gui(int x,int y)
{
int m,i,j,k;
if(x==y)return;
m=(x+y)>>1;
gui(x,m);gui(m+1,y);
i=x;j=m+1;k=x;
while(i<=m&&j<=y){
if(c[i]<=c[j]){
T[k++]=c[i++];
}
else{
T[k++]=c[j++];
tot+=m-i+1;
}
}
while(i<=m)T[k++]=c[i++];
while(j<=y){
T[k++]=c[j++];
tot+=m-i+1;
}
for(i=x;i<=y;i++)
c[i]=T[i];
}

*/                                                                                     归并排序求逆序对;
main()
{
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
cin>>n;
int j;
for(j=1;j<=n;j++){cin>>a[j].sum;a[j].num=j;}
for(j=1;j<=n;j++){cin>>b[j].sum;b[j].num=j;}
sort(a+1,a+n+1,cmp);sort(b+1,b+n+1,cmp);
for(j=1;j<=n;j++)
c[a[j].num]=b[j].num;
gui(1,n);
cout<<tot;
}

不知道为什么测试后最后两个点过不了。


第三题:货车运输

只能说学过的东西忘得太快了,一开始觉得是动态规划,用Dijkstra算法来做,全错。。。

正解是用 最大生成树+贪心,这里用的并查集,过了%60。

先按边权值大小排序,每输入两个需要算的数据就按边权值大小合并边连接的两点,判断输入的数据是否在一个集合内,若在内则该边为解。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
int a,b,z;
};node pp[100005];
int father[100005];
int cmp(const node &a,const node &b){
return a.z>b.z;
}

int find(int x){
if(father[x]!=x)father[x]=find(father[x]);
return father[x];
}
void unionn(int x,int y){
father[find(y)]=find(x);
}
bool judge(int x,int y){
if(find(x)==find(y))return true;
return false;
}
int main()
{
freopen("truck.in","r",stdin);
freopen("truck.out","w",stdout);
int n,m,i,q;
cin>>n>>m;
for(i=1;i<=m;i++)
cin>>pp[i].a>>pp[i].b>>pp[i].z;
cin>>q;
sort(pp+1,pp+m+1,cmp);
while(q--){
for(i=1;i<=n;i++)father[i]=i;
int x,y;
scanf("%d%d",&x,&y);
int k=0;
for(i=1;i<=m;i++)
{
unionn(pp[i].a,pp[i].b);
if(judge(x,y)==true){
printf("%d\n",pp[i].z);k++;
break;
}
}


if(k==0)
printf("-1\n");
}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值