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

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.点和线

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值