【蒻爆了的NOIP系列--普及组复赛】(1)NOIP2010普及组复赛题解

原创 2016年08月30日 18:39:22

这只是一个作业,如果有帮到您的,我只能说。。。这不科学。。。
————————————华丽的分割线————————————
第一题:
第一题题目-第1页
俗话说第一题都是送分的,这题也是。直接暴力就过了,可是本蒻脑洞大开异想天开忘记次药稀里糊涂想都不想就写了个数论。。。
100分做法(暴力)
从起点到终点每个数每位搜一遍累加。。。。。。。
代码(洛谷AC过):

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#define ci const int
#define ri register int
#define ll long long
#define reg register
#define boom return 
#define cmax(a,b) (a)>(b)?(a):(b)
#define cmin(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(i=a;i<b;i++)
using namespace std;

int l,r,ans,z;
int main()
{
    int i,j;

    scanf("%d%d",&l,&r);
    for(i=l;i<=r;i++)
    {
        z=i;
        for(j=0;j<5;j++)ans+=(z%10==2),z/=10;
    }
    printf("%d",ans);
    boom 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌

时间复杂度:O(len*(r-l))
100分做法:(数论)
先设起点为0,终点有n位(如12345)
我们把终点分为1-10000,10001-12000,12001-12300,12301-12340,12341-12345(总之分成5位就对了)
从个位开始,每一位对答案的贡献可以分为两类:1:自身包含2。2:增加之前各个位数的2。
第一类:若该位大于2,贡献为10^该位位数,若小于2,没有贡献,若=2,贡献为去掉该位与更高位以后的数+1(因为还有一个0所以要加1)。
代码:

//由于下载不了数据,本题这种做法没有AC,故没有程序

更新:2016年9月1日
洛谷数据范围题目写错了qwq,再提交一遍就对了qwq。。。

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#define ci const int
#define ri register int
#define ll long long
#define reg register
#define boom return 
#define cmax(a,b) (a)>(b)?(a):(b)
#define cmin(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(i=a;i<b;i++)
using namespace std;

int l,r,a[10],b[10],ans;
int num(int a)
{
    if(a<=0)return 1;
    int i=1;
    while(a--)i*=10;
    return i;
}
int main()
{
    int i,j,k;

    scanf("%d%d",&l,&r),j=--l,k=r;
    for(i=0;i<10;i++)a[i]=l%10,l/=10;
    for(i=0;i<10;i++)b[i]=r%10,r/=10;
    for(i=0;i<10;i++)
    {
        if(a[i]>2)ans-=num(i);
        if(a[i]==2)ans-=j%num(i)+1;
        ans-=num(i-1)*a[i]*i;
    }
    for(i=0;i<10;i++)
    {
        if(b[i]>2)ans+=num(i);
        if(b[i]==2)ans+=k%num(i)+1;
        ans+=num(i-1)*b[i]*i;
    }
    printf("%d",ans);
    boom 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌

时间复杂度:O(len)
————————————华丽的分割线————————————
第二题:
第二题题目-第1页
第二题题目-第2页
都说暴力出奇迹,做1、2题要先想暴力能不能过。做这道题我们可以一秒一秒来计算,首先有10000名同学,每人最多100秒,平均(实际可能有不大的误差)到m个龙头,就有1000000/m秒,每秒把每个龙头都操作一遍,最终时间复杂度就是O(n*平均接水量)可过。
所以这道题就是先把m人安排在m个龙头上,每一秒检查一次龙头有人接完了就换下一个。
喜闻乐见的程序:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#define ci const int
#define ri register int
#define ll long long
#define reg register
#define boom return 
#define cmax(a,b) (a)>(b)?(a):(b)
#define cmin(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(i=a;i<b;i++)
using namespace std;

ci MAXN=10086,MAXM=110;
int n,m,sce[MAXN],wat[MAXM],ok,t;
bool emp(){for(int i=1;i<=m;i++)if(wat[i]>0)return 0;return 1;}
int main()
{
    int i,j;

    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)scanf("%d",&sce[i]);
    for(i=1;i<=m;i++)wat[i]=sce[i];
    while(!emp())
        for(i=1,t++;i<=m;i++)
            if(((wat[i]==0)||!(--wat[i]))&&ok<=n)
                wat[i]=sce[++ok+m];
    printf("%d\n",t);
    boom 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌

————————————华丽的分割线————————————
第三题:
第三题题目-第1页
第三题题目-第2页
首先,这道题算代价的公式很奇怪,我们就从这里开始研究。
首先,我们把一个系统的位置当做左下角,拦截的最远的导弹为右上角组成一个长方形(只是举例。。。)。
然后半径就用勾股算。。。
r=sqrt(a * a+b * b)
那r的平方就是a * a+b* b
于是不用sqrt,这个问题就愉快的解决了。
然后就是愉快的解题时间
我们一看到这题目先想暴力,把所有点按离ab的远近顺序排序(排成两列)然后第一列以半径平方从大到小枚举,每去除一个点就然第二个拦截系统拦。。。
O(n^2)。。。过不了
其实想一想会发现只要按离a的远近顺序排序然后从大到小枚举,记一个max,每去除一个点就更新这些点中离b最远的点的距离。
O(n)。。。
所以。。。
就过了?
就过了。。。
下面程序(洛谷AC,绝不骗人):

#include <cstdio>
#include <cstdlib>
//#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#define ci const int
#define ri register int
#define ll long long
#define reg register
#define boom return 
#define cmax(a,b) (a)>(b)?(a):(b)
#define cmin(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(i=a;i<b;i++)
using namespace std;

ci MAXN=100086;
int x1,y1,x2,y2,n,ans,maxx=-2147483647;
struct node
{
    int x,y;
}a[MAXN];
bool cmp(node a,node b)
{
    return ((x1-a.x)*(x1-a.x)+(y1-a.y)*(y1-a.y))<((x1-b.x)*(x1-b.x)+(y1-b.y)*(y1-b.y));
}
int main()
{
    int i,j;

    scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&n);
    for(i=0;i<n;i++)scanf("%d%d",&a[i].x,&a[i].y);
    sort(a,a+n,cmp);
    ans=(x1-a[n-1].x)*(x1-a[n-1].x)+(y1-a[n-1].y)*(y1-a[n-1].y);
    for(i=n-2;i>=0;i--)
    {
        j=(x1-a[i].x)*(x1-a[i].x)+(y1-a[i].y)*(y1-a[i].y);
        if(maxx<(x2-a[i+1].x)*(x2-a[i+1].x)+(y2-a[i+1].y)*(y2-a[i+1].y))
        maxx=(x2-a[i+1].x)*(x2-a[i+1].x)+(y2-a[i+1].y)*(y2-a[i+1].y);
        if(ans>j+maxx)ans=j+maxx;
    }
    printf("%d",ans);
    boom 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌

————————————华丽的分割线————————————
第四题:
第四题题目-第1页
第四题题目-第2页
第四题题目-第3页
到了最巨最难最坑爹的第4题了,还记得那个阿尔法go吗?没错,这次又是一次激烈的人机对决,不过。。。不过就是计算机的智商低了一点(da)点(jie)。。。
正所谓“以其人之计还治其人之身”,我们就要研究计算机的算法,然后找其弱点而击之。
由于电脑的策略,你选一个武将,电脑就会把这个武将的最好搭档给取走,所以一个武将的最好搭档是拿不到的,但有一个例外:如果你先选一个武将,再选一个最好搭档比那个武将的次好搭档还渣的武将,这时就能取最好搭档了(然而并无卵用,还不如取那个武将的次好搭档)于是,得出结论:刚开始要取次好搭档最好的武将,第二次取到搭档,这时电脑取到了我方第一武将的最好搭档,不过这时电脑要是再取一个武将和电脑第一武将组成比我们的组合还强的组合怎么办?这时就要分开讨论了。
如果真有这种情况,那我们第一武将是电脑第一武将的第几好搭档?显然不是第2好,因为最好的第2好关系被我们拿下了,那第3,4。。。也不可能,那可能是最好搭档吗,如果是,那么他和假设中的比我们的组合还强的组合是什么关系。。。
所以没有这种情况。。。
那么接下来我们就用电脑的策略让他取不到最好组合由于我们有最好的第2好组合所以就ok啦。。。
代码(灰常短):

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#define ci const int
#define ri register int
#define ll long long
#define reg register
#define boom return 
#define cmax(a,b) (a)>(b)?(a):(b)
#define cmin(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(i=a;i<b;i++)
using namespace std;

ci MAXN=520;
int n,a[MAXN][MAXN],ans; 
int main()
{
    int i,j,biggest,big;

    printf("1\n");
    scanf("%d",&n);
    for(i=1;i<=n;i++)for(j=i+1;j<=n;j++)scanf("%d",&a[i][j]),a[j][i]=a[i][j];
    for(i=1;i<=n;i++)
    {
        biggest=big=0;
        for(j=1;j<=n;j++)
            if(a[i][j]>=biggest)big=biggest,biggest=a[i][j];
            else if(a[i][j]>=big)big=a[i][j];
        ans=cmax(big,ans);
    }
    printf("%d",ans); 
    boom 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌

————————————华丽的分割线————————————
最后,让我们膜拜一下我校的大神:xiaoyao24256

版权声明:要拿就拿去~~~加个作者和网址就好了(反正就是一个作业)

相关文章推荐

【用膝盖写代码系列】(1):NOIP2010普及组复赛详解

我知道大家都是苦逼党,照顾到大家,我特地教大家如何用膝盖写代码 第一题:数字统计 题意简述:请统计某个给定范围[L, R]的所有整数中,数字 2 出现的次数。 陷阱提示:这里的”数字2”指的是每...

noip2010普及组复赛测试数据

  • 2015年11月06日 18:26
  • 1.8MB
  • 下载

NOIP2010普及组复赛试题

  • 2012年11月04日 11:34
  • 440KB
  • 下载

noip2016普及组复赛题解

noip2016普及组复赛题解

NOIP2010普及组复赛试题

  • 2013年10月19日 10:40
  • 340KB
  • 下载

[NHZXOI2017]2016NOIP普及组复赛题解

用了两天的中午时间做了一套今年的普及组复赛试题结果测出来分数只有两百!(第三题洛谷全过,lemon却显示编译错误,奇了怪了) 第一题  买铅笔 题目来源:洛谷P1909 考查知识点:数学 解题思路:把...

NOIP2010普及组复赛试题

  • 2012年01月14日 21:34
  • 1.24MB
  • 下载

【用膝盖写代码系列】(5):NOIP2013普及组复赛详解

有人问我为什么2013在2014之后? 那是因为。。。。。。你丑(这句划掉) 2013年难啊! …… 第一题:计数问题 题面简述:试计算在区间 1 到 n 的所有整数中,数字 x(0 ≤...

【用膝盖写代码系列】(2):NOIP2011普及组复赛详解

这里是NOIP2011的急救现场,我已经准备好了救护车。 那么我们从第一题开始 第一题:数字反转 题意简述:给一个不超过10位的数(包括负号),输出这个数的反转。 (如:123,输出321)陷...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【蒻爆了的NOIP系列--普及组复赛】(1)NOIP2010普及组复赛题解
举报原因:
原因补充:

(最多只允许输入30个字)