您的位置:首页 > 其它

7.14

2016-07-14 20:28 302 查看
noip模拟赛(鬼知道是哪个学校的→.→)。

第一题:LGTB 玩扫雷

在一个n m 的棋盘上,有位置上有雷(用“*” 表示),其他位置是空地(用“.” 表示)。

LGTB 想在每个空地上写下它周围8 个方向相邻的格子中有几个雷。

请帮助他输出写了之后的棋盘

爆搜,不说了。

#include<cstdio>

#include<iostream>

#include<cstring>

using namespace std;

int move[2][8]={{-1,-1,-1,0,0,1,1,1},{-1,0,1,-1,1,-1,0,1}};

char s[1005][1005];

int map[1005][1005];

int main()

{
freopen("mine.in","r",stdin);
freopen("mine.out","w",stdout);
int n,m,i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
cin>>s[i][j];
if(s[i][j]=='*')
for(int k=0;k<=7;k++)
map[i+move[0][k]][j+move[1][k]]++;
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(s[i][j]=='*')
printf("*");
else
{
printf("%d",map[i][j]);
}
}
printf("\n");
}

}

第二题:LGTB 学分块

LGTB 最近在学分块,但是他太菜了,分的块数量太多他就混乱了,所以只能分成3 块

今天他得到了一个数组,他突然也想把它分块,他想知道,把这个数组分成3 块,块可以为空。假设3 块各

自的和中的最大值最小

请输出分完之后3 块中的最大值

暴力方法过得了7个点,用前缀和。

#include<cstdio>

#include<iostream>

#include<cstring>

using namespace std;

long long a[100005];

main()

{
freopen("divide.in","r",stdin);
freopen("divide.out","w",stdout);
int n,i;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
a[i]+=a[i-1];
}
long long maxn=max(max(a[n/3],a[(n/3)*2]-a[n/3]),a
-a[(n/3)*2]);
if(a[n/3]<a[(n/3)*2]-a[n/3]||a[n/3]<a
-a[(n/3)*2])
for(i=n/3;i<=n-2;i++)
{
if(a[i]>maxn)break;
int x,y,z;
for(int j=i+1;j<=n-1;j++)
{
x=a[i];y=a[j]-a[i];
z=a
-a[j];
if(x>maxn||y>maxn||z>maxn)continue;
maxn=max(max(x,y),z);
}
}
else 
for(i=1;i<=n/3;i++)
{
if(a[i]>maxn)break;
int x,y,z;
for(int j=i+1;j<=n-1;j++)
{
x=a[i];y=a[j]-a[i];
z=a
-a[j];
if(x>maxn||y>maxn||z>maxn)continue;
maxn=max(max(x,y),z);
}
}
printf("%I64d",maxn);

}

正解用二分法

#include <set>

#include <cmath>

#include <stack>

#include <cstdio>

#include <cstring>

#include <iostream>

#include <algorithm>

#include <cstdlib>

#include <numeric>

#include <vector>

#include <ctime>

#include <queue>

#include <list>

#include <map>

#define pi acos(-1.0)

#define INF 0x3f3f3f3f

#define clr(x)  memset(x,0,sizeof(x));

#define clrto(x,siz,y)  for(int xx=0;xx<=siz;xx++)  x[xx]=y;

#define clrset(x,siz)  for(int xx=0;xx<=siz;xx++)  x[xx]=xx;

#define clr_1(x) memset(x,-1,sizeof(x));

#define clrmax(x) memset(x,0x3f,sizeof(x));

#define clrvec(x,siz) for(int xx=0;xx<=siz;xx++)  x[xx].clear();

#define fop2   freopen("divide.in","r",stdin); freopen("divide.out","w",stdout);

#define fop   freopen("in.txt","r",stdin);freopen("in2.txt","w",stdout);

#define myprogram By_135678942570

#define clrcpy(x,siz,y)  for(int xx=0;xx<siz;xx++)  x[xx]=y[xx];

#define pb push_back

#ifdef WIN32

#define AUTO "%I64d"

#else

#define AUTO "%lld"

#endif

using namespace std;

long long num[1000111];

long long sum[1001011];

int main()

{
fop2;
int T,cas=0;
clr(sum);
int N;
scanf("%d", &N);
for(int i=1;i<=N;i++)
{
scanf(AUTO, &num[i]);
sum[i]=sum[i-1]+num[i];
}
long long res=0x3f3f3f3f3f3f3f3fll;
for(int i=1;i<=N;i++)
{
long long sum1=sum[i-1];
int l=i+1,r=N+1;
while(l<r-1)
{
int m=l+r>>1;
if(sum[m-1]-sum1<=sum
-sum[m-1])
l=m;
else r=m;
}
// cerr<<"~~~"<<i<<endl;
long long sum2=sum[l-1]-sum1;
long long sum3=sum
-sum[l-1];
res=min(res,max(sum1,max(sum2,sum3)));
sum2=sum[l]-sum1;
sum3=sum
-sum[l];
res=min(res,max(sum1,max(sum2,sum3)));
}printf(AUTO, res);
printf("\n");

}

对前面一大堆我很恶心→.→

第三题:LGTB 玩THD

LGTB 最近在玩一个类似DOTA 的游戏名叫THD

有一天他在守一座塔,对面的N 个小兵排成一列从近到远站在塔前面

每个小兵有一定的血量hi,杀死后有一定的金钱gi

每一秒,他都可以攻击任意一个活着的小兵,对其造成P 点伤害,如果小兵的血量低于1 点,小兵死亡,他

得到金钱。他也可以不攻击任何小兵。

每一秒LGTB 攻击完毕之后,塔会攻击距离塔最近的一个活着的小兵,对其造成Q 点伤害,如果小兵的血

量低于1 点,小兵死亡,LGTB 不会得到金钱

现在LGTB 想知道,在他选择最优策略时,他能得到多少钱。

深搜只能得30分。不过数据特别水,直接输出随机函数过得了25分,直接输出0过得了30分(我写了半天深搜才过30分⊙﹏⊙),更6的是把每个兵的金钱加起来直接输出过得了65分!!学到了。

代码就不附了。正解动态规划(最不擅长。。)

今天博客比较水,因为题也不算难。(码了一上午的暴力艾玛)

另附昨日晚调出的题:vijos p1782(noip提高组2012),线段树。(凑字数用)

在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。

面对海量租借教室的信息,我们自然希望编程解决这个问题。我们需要处理接下来n天的借教室信息,其中第i天学校有ri个教室可供租借。共有m份订单,每份订单用三个正整数描述,分别为dj,sj,tj,表示某租借者需要从第sj天到第tj天租借教室(包括第sj天和第tj天),每天需要租借dj个教室。 

我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。

借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第sj天到第tj天中有至少一天剩余的教室数量不足dj个。

现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。
用线段树保存每个区间的最小值,然后该怎么写怎么写。(语文不好解释不清)
#include<cstdio>

#include<iostream>

#include<cstring>

#include<algorithm>

#define L(u)(u<<1)

#define R(u)(u<<1|1)

using namespace std;

const int MAXN=1000000+5;

int r[MAXN],i;

struct mode{
int l,r,minx,add;

};

mode node[MAXN*4];

void pushdown(int u)

{
node[L(u)].add+=node[u].add;
node[L(u)].minx-=node[u].add;
node[R(u)].add+=node[u].add;
node[R(u)].minx-=node[u].add;
node[u].add=0;

}

void pushup(int u)

{
node[u].minx=min(node[L(u)].minx,node[R(u)].minx);
return;

}

void build(int u,int left,int right)

{
node[u].l=left;node[u].r=right;
if(left==right)
{
node[u].minx=r[left];
return ;
}
int mid=(left+right)>>1;
build(L(u),left,mid);
build(R(u),mid+1,right);
pushup(u);

}

void update(int u,int left,int right,int val)

{
if(left<=node[u].l&&node[u].r<=right)
{
pushdown(u);
node[u].add+=val;
node[u].minx-=val
;
return ;
}
if(node[u].add)pushdown(u);
int mid=(node[u].l+node[u].r)>>1;
if(mid>=right)update(L(u),left,right,val);
else if(mid<left)update(R(u),left,right,val);
else
{
update(L(u),left,mid,val);
update(R(u),mid+1,right,val);
}
pushup(u);

}

int main()

{
int n,m;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&r[i]);
build(1,1,n);
for(i=1;i<=m;i++)
{
int d,s,t;
scanf("%d%d%d",&d,&s,&t);
update(1,s,t,d);
if(node[1].minx<0)
{
printf("-1\n%d",i);return 0;
}
}
printf("0");

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