您的位置:首页 > 其它

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

2016-08-30 18:39 609 查看
这只是一个作业,如果有帮到您的,我只能说。。。这不科学。。。

————————————华丽的分割线————————————

第一题:



俗话说第一题都是送分的,这题也是。直接暴力就过了,可是本蒻脑洞大开异想天开忘记次药稀里糊涂想都不想就写了个数论。。。

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题要先想暴力能不能过。做这道题我们可以一秒一秒来计算,首先有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;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌


————————————华丽的分割线————————————

第三题:





首先,这道题算代价的公式很奇怪,我们就从这里开始研究。

首先,我们把一个系统的位置当做左下角,拦截的最远的导弹为右上角组成一个长方形(只是举例。。。)。

然后半径就用勾股算。。。

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;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌


————————————华丽的分割线————————————

第四题:







到了最巨最难最坑爹的第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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  2010