【UKIEPC2015 M】【暴力匹配+SET去重】Milestone Counter 匀速行驶 合法的里程碑起点

#include<stdio.h> 
#include<iostream>
#include<string.h>
#include<vector>
#include<sstream>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
typedef long long LL;
const int N=1e3+10;
int n,m;
LL t[N],a[N],d[N],b[N];
LL gcd(LL x,LL y)
{
    return y==0?x:gcd(y,x%y);
}
set<LL>sot;
set<LL>::iterator it;
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++)scanf("%lld",&t[i]);
        for(int i=1;i<n;i++)a[i]=t[i+1]-t[i];
        for(int i=1;i<=m;i++)scanf("%lld",&d[i]);
        for(int i=1;i<m;i++)b[i]=d[i+1]-d[i];

        sot.clear();
        for(int i=1;i<m;i++)
        {
            if(i+n-1>m)break;//起点可以是[1,m-1],段数有n-1,即i+n-1-1<=m-1,即i+n-1<=m
            LL g=gcd(a[1],b[i]);
            LL zi=a[1]/g;
            LL mu=b[i]/g;
            bool flag=1;
            for(int j=2;j<n;j++)
            {
                LL g=gcd(a[j],b[i+j-1]);
                LL x=a[j]/g;
                LL y=b[i+j-1]/g;
                if(x!=zi||y!=mu)
                {
                    flag=0;
                    break;
                }
            }
            if(flag)sot.insert(b[i]);
        }
        printf("%d\n",sot.size());
        for(it=sot.begin();it!=sot.end();it++)printf("%lld ",*it);
        puts("");
    }
    return 0;
}
/*
【trick&&吐槽】
1,不同的数筛掉,用set很方便
2,要防止区间溢出
3,判定是否a/b=x/y,直接把两个分数都化成最简,然后比较"分子=分子,分母=分母"即可

【题意】
一共有n(1e3)个里程碑,告诉你这n个里程碑代表的点的坐标(抽象到x轴正半轴上,坐标为[0,1e15]的整数)
然后我们驾车,匀速驶过了连续m个里程碑。
忘记了驶过的是哪m个,但是我们记得驶过这m个里程碑的时刻(时刻也为[0,1e15]的整数)
问你所有可能的车速的种类,并输出所有情况下行车驶过的第一段路程的长度。

【类型】
暴力,gcd

【分析】
看到这题n的范围,我们想到O(n^2)的做法即可实现这道题。
就是枚举匹配的首位点,然后向后延展,严格匹配m-1个区间。
如果这m-1个区间的时间与距离的比例都相同。那么这就可能是一个合法的区间。
于是这样暴力即可AC这道题

【时间复杂度&&优化】
O(n^2)

【数据】
input
4 12
1 2 4 5
6 8 12 18 26 28 30 34 36 37 39 40
output
2
1 2

input
5 10
1 2 3 4 5
0 1 2 3 4 5 6 7 8 9
output
1
1

input
3 6
1 2 4
11 12 15 19 24 30
output
0

input
2 3
1123456789000 1123456789007
5 8 13
output
2
3 5
*/

你可能感兴趣的:(算法,ACM,ICPC)