7.14

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[n]-a[(n/3)*2]);
if(a[n/3]<a[(n/3)*2]-a[n/3]||a[n/3]<a[n]-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[n]-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[n]-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[N]-sum[m-1])
l=m;
else r=m;
}
// cerr<<"~~~"<<i<<endl;
long long sum2=sum[l-1]-sum1;
long long sum3=sum[N]-sum[l-1];
res=min(res,max(sum1,max(sum2,sum3)));
sum2=sum[l]-sum1;
sum3=sum[N]-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");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值