您的位置:首页 > 其它

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

2016-09-04 07:00 537 查看
这只是一个作业,如果有帮到您的,我只能说。。。这不科学。。。

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

第一题:



一看就懵了。。。

第一题什么时候这么恶心了。。。

然后看数据范围。。。

于是只要开个10000的数组记i有木有在n个正整数中出现过,

然后再双重循环枚举数就行了。。。

唉好像有什么不对。。。

如果数据是:

5

1 2 3 4 5

那么正确答案是3:

1+2=3 1+3=4

1+4 和2+3=5

但程序会认为是4个答案

于是输出4.。。

所以还要开个10000的数组记哪些答案已经有了。。。

代码酱:

#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*2;
int a[100],n,ans;
bool cmap[MAXN],ansmap[MAXN];
int main()
{
int i,j;

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


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

第二题:




这道题看起来像各种数论等noi级题实际上看一看L顿时茅塞顿开了。。。

由于L超级小,于是我们可以枚举ab再根据题意判断是否成立。开个min找差值最少的ab组合输出。。。

(墙裂建议吧所有(包括ij)变量都开成double)

代码呵呵呵:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#include <climits>
#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;

double a,b,l,ansa=0,ansb=0,minn=2147483647;
int main()
{
double i,j;

cin>>a>>b>>l;
double pro=a/b;
for(i=1;i<=l;i++)
for(j=1;j<=l;j++)
{
if((i/j)>=pro&&abs((i/j)-pro)<minn)
ansa=i,ansb=j,minn=abs((i/j)-pro);
}
cout<<(int)ansa<<" "<<(int)ansb;
return 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌


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

第三题:



以前也有这种题目,不过n效率很多而且要打印矩阵,想想那时候是整么做的。。。

那时是不是列一个矩阵然后弄一个类似蛇的东西遇到墙(数字)就右转对不对?

所以到这道题中没必要一个一个数字贴上去只要记一个ans级当前的数按照这个思路先看蛇会不会在撞倒墙前撞倒要找的点,有的话就计算距离+到ans里否则算这里到墙有多远+入答案然后右转。

不过有一种有趣的东西。。。

你会发现撞倒终点前的ans增加的很奇怪

比如n=6:

+6,+5,+5,+4,+4,+3,+3,+2,+2,+1,+1

于是愉快的优化一下。。。

代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#include <climits>
#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 n,a,b,ans=0;
int main()
{
int x,y;

scanf("%d%d%d",&n,&a,&b);
x=1,y=0;
while(1)
{
if(x==a){ans+=b-y;break;}
else ans+=n,y+=n,n--;
if(y==b){ans+=a-x;break;}
else ans+=n,x+=n;
if(x==a){ans+=y-b;break;}
else ans+=n,y-=n,n--;
if(y==b){ans+=x-a;break;}
else ans+=n,x-=n;
}
printf("%d",ans);
return 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌


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

第四题:





子~巨~阵~

先想想暴力~

枚举行列然后一个个计算。。。

O(n*m*n!*m!)

刚好到了极限的样子qwq。

可是由于各种常数及noip评测机的蜗牛速度(等下,这句话划掉)。。。

所以我们要另外找方法。。。

一种dp:

记b[i]为第i行的分值,c[i][j]为第i,j行合并增加的分值。。。

f[i][j]=放了i-1行最后一行是j的最小答案

方橙:f[i][j]=cmin(f[i][j],f[i-1][k]+c[k][j]+b[j])|k=i-1~j

可是行列都这样搞会狗。。。

于是就DFS行DP列

代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <map>
#include <climits>
#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=20;
int n,m,x,y,ans=2147483647,a[MAXN][MAXN],f[MAXN][MAXN],b[MAXN],c[MAXN][MAXN],vis[MAXN];
inline void Dfs(int now,int tot)
{
ri i,j,k;
if((now>n&&tot<x)||n-now+1<x-tot)return;
if(tot==x)
{
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
memset(f,0X7F,sizeof(f));
for(i=1;i<=m;i++)for(j=1;j<x;j++)
b[i]+=abs(a[vis[j]][i]-a[vis[j+1]][i]);
for(i=1;i<=m;i++)for(j=i+1;j<=m;j++)for(k=1;k<=x;k++)
c[i][j]+=abs(a[vis[k]][i]-a[vis[k]][j]);
for(i=1;i<=y;i++)for(j=i;j<=m;j++)
if(i==1)f[i][j]=b[j];
else for(k=i-1;k<j;k++)
f[i][j]=cmin(f[i][j],f[i-1][k]+c[k][j]+b[j]);
for(i=y;i<=m;i++)ans=cmin(ans,f[y][i]);
return;
}
Dfs(now+1,tot);
vis[tot+1]=now;
Dfs(now+1,tot+1);
}
int main()
{
ri i,j;

scanf("%d%d%d%d",&n,&m,&x,&y);
for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&a[i][j]);
Dfs(1,0);
printf("%d",ans);
return 0;
}
//没有什么是两个巴掌不能解决的,如果有就再来两个巴掌


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

好惨没有写DP的经验qwq
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: