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取模,转10就是现在的位置编号加上m的10次方就好了

这样就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座城市,编号从 1n,城市之间有 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 ** 。

输出格式

共有 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出1。

 

 

这个。。emmm...不会。。实际上题目也没太读懂。。

求助了yxt dalao,终于理解了题意,但做法大体会了一点,还是好多点不懂

posted @ 2019-11-09 16:41  攒一兜星星*  阅读(175)  评论(0编辑  收藏  举报