2016.8.9测试解题报告(combo,joseph,bomb,lines)

来源:互联网 发布:淘宝宝贝推荐排序 编辑:程序博客网 时间:2024/05/16 10:47

1.连续自然数和(LuoguP1147)

题目描述:
对一个给定的自然数M,求出所有的连续的自然数段,这些连续的自然数段中的全部数之和为M。
例子:1998+1999+2000+2001+2002 = 10000,所以从1998到2002的一个自然数段为M=10000的一个解。

思路:
纯数学的水题,分两种情况进行讨论:把给定的数分为奇数份或将给定的数分为偶数份。当分为奇数份时,先检查时候能正好分为i份,如果能则确定中位数,并顺次确定头和尾。当分为偶数份时,找到中位数之前的那个数并找到头和尾。至于答案的顺序问题,只要从分的份数从多到少就可以保证首位数字从小到大(想一想,为什么)。

代码:

/*2016.8.9 BulaBulaCHN*/#include<cstdio>#include<cstdlib>#include<cmath>#include<algorithm>#include<string>#include<cstring>#include<iostream>using namespace std;int m;int main(){    freopen("combo.in","r",stdin);    freopen("combo.out","w",stdout);    scanf("%d",&m);    for(int i=m;i>=2;i--)    {        if(i%2==1)        {            int mid=m/i;            if(mid*i!=m) continue;            if(mid>=i/2) printf("%d %d\n",mid-i/2,mid+i/2);        }        else if(i%2==0)        {            double mid=(double)m/i;            if(mid-(int)m/i!=0.5000) continue;            int md=(int)mid;            if(md-i/2+1>=0) printf("%d %d\n",md-i/2+1,md+i/2);        }    }    fclose(stdin);    fclose(stdout);    return 0;}

2.约瑟夫(LuoguP1145)

题目描述:
n个人站成一圈,从某个人开始数数,每次数到m的人就被杀掉,然后下一个人重新开始数,直到最后只剩一个人。现在有一圈人,k个好人站在一起,k个坏人站在一起。从第一个好人开始数数。你要确定一个最小的m,使得在第一个好人被杀死前,k个坏人先被杀死。

思路:
看到这个题想到的当然还是模拟了,因为第一眼看的时候数据范围只有14嘛……结果到11的时候我就(机智地)发现纯模拟肯定是T了。在这里我提供两种优化的思路:第一种,运用链表,可以迅速的进行删除操作,也省去了很多多余的数数操作;第二种,每删除一个点更新一下人数t,用当前位置+步数mod当前人数就是下一个被删除的人(比较快)。

代码:

#include<cstdio>#include<iostream>using namespace std;int a[16];bool fun(int k,int m)//确定两阵营各有k人步长为m时是否合法{    int s=0;    int t=2*k;    for(int i=1;i<=k;i++)//正好删除k个人    {        s=(s-1+m)%t;//走一步,取余        t--;//删去一人        if(s<k) return false;//删除好人,不合法    }    return true;}int main(){    int i,j;    for(i=1;i<=13;i++)//把所有情况处理出来    {        j=i+1;        while(!fun(i,j))            j++;        a[i]=j;    }    int k;    while(cin>>k && k)//hh        cout<<a[k];    return 0

为什么要都一起打个表然后再输出呢?呵呵,就是告诉你们它有多快。
这里写图片描述

3.轰炸(LuoguP1142)

题目描述:
“我该怎么办?”飞行员klux向你求助。
事实上,klux面对的是一个很简单的问题,但是他实在太菜了。
klux要想轰炸某个区域内的一些地方,它们是位于平面上的一些点,但是(显然地)klux遇到了抵抗,所以klux只能飞一次,而且由于飞机比较破,一点起飞就只能沿直线飞行,无法转弯。现在他想一次轰炸最多的地方。

思路:
其实就是给出一个点集让你求同一条直线上最多有多少个点。其实在一顿狂导公式之后就已经非常的水了。还有不要觉得是O(n^3)就会T,自己看看时间。因为每次扫描一个点都只是O(n)的复杂度。

代码:

#include<cstdio>#include<cstdlib>#include<cmath>#include<algorithm>#include<string>#include<cstring>#include<iostream>using namespace std;struct point{    int x,y;};point a[705];int n=1;int ans=0;int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);    for(int i=1;i<=n;i++)        for(int j=i+1;j<=n;j++)    {        int t1=a[i].x-a[j].x;        int t2=a[i].y-a[j].y;        int judge=a[j].x*a[i].y-a[i].x*a[j].y;        int po=0;        for(int k=1;k<=n;k++)            if(a[k].x*t2-a[k].y*t1==judge) po++;//不懂公式请自己导        ans=max(ans,po);    }    printf("%d\n",ans);    return 0;}

这里写图片描述

4.点和线

拒绝写跨立实验这种恶心题解……

1 0
原创粉丝点击