2014 day1
总:忘了快速幂,离散化不熟,读不懂题(其实还是知识点不熟,基础不牢吧)
1.转圈游戏
读题可以发现
0->m m = ( 0+m)%n
1->m+1 m+1 = (m+1)%n
... ...
n-m->0 0 = (n-m+m)%n
n-m+1->1 1 = (n-m+1+m)%n
哇塞好像发现了什么不得了的事情
某人转一次之后的位置编号就是现在的位置编号加上m再对n取模
好啦,题目给了总人数n,给了m,给了转的总轮数10k,还给了某人当前位置编号x
emmm....好像不太对,k<109,所以......轮数是<10k^9 的.....这数有点大啊....
emm....嗷我突然想起来一个小剪枝:
他们转转转总会有转到原位置的一次吧,嗯对,那就先找到他转到原位置需要几轮,再用总轮数对它取模,
得到的就是实际需要看的轮数了,因为那些转转转都回到了原位置等于白转
所以,我就打了这样的代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,k,x,now/*现在在几号位置*/,per/*转回原位置需要的轮数*/;
ll tot=1;//去掉转回原位置的所有轮数,剩余实际需要看的
int main(){
scanf("%d%d%d%d",&n,&m,&k,&x);
for(int i=0;i<n;i++){
now=(now+m)%n;
per++;
if(now==0) break;
}
for(int i=1;i<=k;i++)
tot=tot*10%per;
while(tot--)
x=(x+m)%n;
printf("%d",x);
return 0;
}
然后,成功T了一个点。。。
然鹅,,,快速幂啊!!!也不用取余了,直接快速幂求10k,再套用公式,只要随时取模,就不会爆。。米有想到快速幂
某人转一次之后的位置编号就是现在的位置编号加上m再对n取模,转10k 就是现在的位置编号加上m的10k 次方就好了
这样就A了嘛。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,k,x;
ll ans;
int qpow(int a, int b, int q) {
ll s = 1;
while (b) {
if (b & 1)
s = s * a % q;
a = (ll)a * a % q;
b >>= 1;
}
return s;
}
int main(){
scanf("%d%d%d%d",&n,&m,&k,&x);
ans=( x%n + m%n * qpow(10,k,n)%n ) %n;
printf("%lld",ans);
return 0;
}
2.火柴排队
就是让a,b数组中第i大的两个对应,答案就是最小的了
关键关键!u[b[i].xu]=a[i].xu
这利用了下标的单调升序。
可以发现u数组下标都是1~n,b数组中每个数的顺序也都是1~n的正整数,a数组同样如此。
那么对u数组进行归并排序之后,可以发现u数组中的值就是:u[1]=1,u[2]=2......u[n]=n对吧?
那么也就是说,对u数组进行归并排序就是为了让u[i]=i,也就是说,让b数组中第i小的数和a数组中第i小的数在同一个位置。
再加上归并排序模板就好了哈哈
#include<bits/stdc++.h>
using namespace std;
const int mod=99999997;
const int N=1000005;
int n,u[N],v[N];
long long cnt;
struct node{
int h,xu;
}a[N],b[N];
bool cmp(node x,node y) { return x.h < y.h;}
void merge_sort(int l, int r) { //归并排序模板呐~~哈哈
if(l<r) {
int mid=(l+r)/2;
merge_sort(l,mid);
merge_sort(mid+1,r);
int k=l;
int p=l,q=mid+1;
while(p<=mid||q<=r){
if(q>r||(p<=mid&&u[p]<=u[q]))
v[k++]=u[p++];
else {
v[k++]=u[q++];
cnt += (mid-p+1); //将逆序对的个数累加起来
cnt %= mod;
}
}
for (int i=l;i<=r;i++)
u[i]=v[i];
}
}
int main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i].h);
a[i].xu=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
scanf("%d",&b[i].h);
b[i].xu=i;
}
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++)
u[b[i].xu]=a[i].xu;
merge_sort(1,n);
printf("%lld",cnt);
return 0;
}
3.货车运输
题目描述
A国有n座城市,编号从 1到n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入格式
第一行有两个用一个空格隔开的整数n,m,表示 A 国有n 座城市和 m 条道路。
接下来 m行每行3个整数 x,y,z,每两个整数之间用一个空格隔开,表示从 x号城市到y号城市有一条限重为 z 的道路。注意: ** x 不等于 y,两座城市之间可能有多条道路 ** 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: ** x 不等于 y ** 。
输出格式
共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出−1。
这个。。emmm...不会。。实际上题目也没太读懂。。
求助了yxt dalao,终于理解了题意,但做法大体会了一点,还是好多点不懂