Test 2018-07-20 二中集训

Black Rock Shooter

原题:SPOJ GSS3

$ \rightarrow $ 戳我进SPOJ原题
 

$ 1. $ 题目大意

在人气动漫 $ Black Rock shooter $ 中,当加贺里对麻陶说出了“滚回去“以后,与此同时,在另一个心灵世界里, $ BRS $ 也遭到了敌人的攻击。此时,一共有 $ n $ 个攻击排成一行朝着她飞了过来,每个攻击有一个伤害值。并且每个攻击伤害可能随时变化。$ BRS $ 的攻击可以打掉一段连续的攻击。现在,给出 $ m $ 段攻击,求出 $ BRS $ 最多可以打掉此段里多少的伤害(就是说从给定一段里选择连续一段打 掉)。伤害从 $ 1 $ 到 $ n $ 编号。

BRS
 

$ 2. $ 输入格式

第一行 $ 2 $ 个整数:$ n , m $

第二行 $ n $ 个数:第 $ i $ 个数代表第 $ i $ 个攻击 第 $ 3 $ 到 $ 2+m $ 行:每行三个数 $ k,x,y $ 。

若 $ k=1,x,y $ 代表查询的区间。

若 $ k=2,$ 代表第 $ x $ 个攻击伤害改为了 $ y $ 所有的伤害值绝对值 $ \le 1000 $
 

$ 3. $ 输出格式

对于每次 $ k=1 $ ,输出一个整数代表最大值
 

$ 4. $ 样例输入

 5 3
 1 2 -3 4 5
 1 2 3
 2 2 -1
 1 2 3

$ 5. $ 样例输出

 2 
 -1 

 

$ 6. $ 数据范围

对于 $ 20 % $ 的数据:$ n,m \le 100 $

对于 $ 60 % $ 的数据:$ n,m \le 3000 $

对于 $ 100 % $ 的数据:$ n \le 500000,m \le 100000 $

 

题解

  • 题意:给定长度为 $ N $ 的数串,$ M $ 个询问,查询 $ [a,b] $ 中的最大连续子段和。

  • 线段树上维护4个值的信息

    • 区间和 $ sum $
      最大子段和 $ max $
      左端开始的最大子段和 $ lmax $
      右端开始的最大子段和 $ rmax $
  • 合并过程见代码
     

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<algorithm>
#define ll long long
using namespace std;
struct btree{
    ll l,r,book;
    ll mx,sum,lx,ly;
}tr[2000000];
ll n,m,k,x;
ll y;
void buildtree(ll l,ll r,ll now){
    tr[now].l=l;tr[now].r=r;
    if(l==r){
        scanf("%lld",&tr[now].sum);
        tr[now].mx=tr[now].lx=tr[now].ly=tr[now].sum;
        return;
    }
    ll mid=(l+r)>>1;
    buildtree(l,mid,now<<1);
    buildtree(mid+1,r,now<<1|1);
    tr[now].sum=tr[now<<1].sum+tr[now<<1|1].sum;
    tr[now].mx=max(max(tr[now<<1].mx,tr[now<<1|1].mx),tr[now<<1].ly+tr[now<<1|1].lx);
    tr[now].lx=max(tr[now<<1].lx,tr[now<<1].sum+tr[now<<1|1].lx);
    tr[now].ly=max(tr[now<<1|1].ly,tr[now<<1|1].sum+tr[now<<1].ly);
}
void updata(ll x,ll now,ll val){
    if(tr[now].l==x&&tr[now].r==x){
        tr[now].mx=tr[now].sum=tr[now].lx=tr[now].ly=val;
        return;
    }
    ll mid=(tr[now].l+tr[now].r)>>1;
    if(x>mid) updata(x,now<<1|1,val);
    else updata(x,now<<1,val);
    tr[now].sum=tr[now<<1].sum+tr[now<<1|1].sum;
    tr[now].mx=max(max(tr[now<<1].mx,tr[now<<1|1].mx),tr[now<<1].ly+tr[now<<1|1].lx);
    tr[now].lx=max(tr[now<<1].lx,tr[now<<1].sum+tr[now<<1|1].lx);
    tr[now].ly=max(tr[now<<1|1].ly,tr[now<<1|1].sum+tr[now<<1].ly);
}
btree query(ll l,ll r,ll now){
    if(tr[now].l==l&&tr[now].r==r){return tr[now];}
    ll mid=(tr[now].l+tr[now].r)>>1;
    if(l>mid){return query(l,r,now<<1|1);}
    else if(r<=mid) {return query(l,r,now<<1);}
    else {
        btree lo,ro,no;
        lo=query(l,mid,now<<1);
        ro=query(mid+1,r,now<<1|1);
        no.sum=lo.sum+ro.sum;
        no.mx=max(max(lo.mx,ro.mx),lo.ly+ro.lx);
        no.lx=max(lo.lx,lo.sum+ro.lx);
        no.ly=max(ro.ly,ro.sum+lo.ly);
        return no;
    }
}
int  main(){
    scanf("%lld %lld",&n,&m);
    buildtree(1,n,1);
    for(ll i=0;i<m;i++){
        scanf("%lld %d %lld",&k,&x,&y);
        if(k==1){printf("%lld\n",query(x,y,1).mx);}
        else{updata(x,1,y);}
    }
    return 0;
}

Fy's dota2

 

$1. $ 题目大意

$ Fy $ 觉得自己玩 $ cf,lol $ 这种高端游戏已经够厉害了,于是他决定去玩 $ dota2. $ 结果 $ fy $ 的鼠标右键坏了,所以他就等到 $ 2250 $ 买了把闪烁匕首,用跳刀前进,准备去送泉水。但 是 $ fy $ 一次最多前进 $ k $ 的距离,泉水离 $ fy $ 现在的距离是 $ n $ 。 $ Fy $ 想知道他到泉水的方案数。

dota2
 

$ 1. $ 输入格式:

第一行 $ 2 $ 个整数:$ k,n $
 

$ 2. $ 输出格式:

一行 $ 1 $ 个整数:代表答案对 $ 7777777 $ 取膜的结果
 

$ 3. $ 样例输入:

 2 4 

$ 4. $ 样例输出

 5 

 

$ 5. $ 样例解释

一共有 $ 5 $ 种方案

$ →1→2→3→4 $
$ →2→3→4 $
$ →2→4 $
$ →1→3→4 $
$ →1→2→4 $
 

$ 6. $ 数据范围

对于 $ 30 % $ 的数据:$ n \le 1000,k \le 10 $

对于 $100 % $ 的数据:$ 1 \le n \le 2^31 -1,1 \le k \le 10 $
 

题解

  • 递推公式十分明显:

  • $ F[i] $ 代表走的距离为 $ i $ 时的方案数

  • $ F[i]= \sum_{j=i-k}^{i-1} F[j] (F[0]=1) $

  • 由于 $ n $ 较大,直接使用矩阵加速优化即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define mod 7777777
int k,n;
ll ans,f[11]={0,1,2,4,8,16,32,64,128,256,512};
struct matrix{ ll a[11][11]; }st,rec;
inline matrix X(matrix x,matrix y){
	matrix c;
	memset(c.a,0,sizeof(c.a));
	for(int i=1;i<=k;++i)
		for(int j=1;j<=k;++j)
			for(int l=1;l<=k;++l)
				c.a[i][j]=(c.a[i][j]+(x.a[i][l]*y.a[l][j])%mod)%mod;
	return c;
}
inline matrix qpow(matrix x,int s){
	matrix res=x; --s;
	while(s){
		if(s&1) res=X(res,x);
		x=X(x,x);
		s>>=1;
	}
	return res;
}
int main(){
	freopen("fyfy.in","r",stdin);
	freopen("fyfy.out","w",stdout);
	scanf("%d %d",&k,&n);
	if(n<=k){ puts("1"); return 0; }
	for(int i=1;i<k;++i) st.a[i][i+1]=1;
	for(int i=1;i<=k;++i) st.a[k][i]=1;
	rec=qpow(st,n-k);
	for(int i=1;i<=k;++i) ans=(ans+(f[i]*rec.a[k][i])%mod)%mod;
	printf("%d",ans);
	return 0;
}

Olddriver’s books

原题:POJ 1151 Atlantis (原题坐标和面积是带小数点的)

$ \rightarrow $ 戳我进POJ原题
 

$ 1. $ 题目大意:

$ Olddriver $ 的书多的吓人,什么算法导论,组合数学英文版 \((orz)\) 。。。。。。他把 $ n $ 本书都放在身后的桌子上, 每本书有一定的面积,并且书可以覆盖,求 $ n $ 本书覆盖桌面的面积

olddriver
 

$ 2. $ 输入格式:

输入第一行为一个数 $ N $ ,表示书的数量。

下面 $ N $ 行,每行 四个整数,分别表示每个书的左下角和右上角的坐标。
 

$ 3. $ 输出格式:

输出只有一行,一个整数,表示图形的面积。
 

$ 4. $ 样例输入:

 3 
 1 1 4 3 
 2 -1 3 2 
 4 0 5 2 

$ 5. $ 样例输出:

 10 

 

$ 6. $ 数据范围:

对于 $ 30 % $ 的数据:$ n \le 100 $ ,坐标数值绝对值 $ \le 300 $

对于 $ 100 % $ 的数据:$ n \le 100 $ ,坐标数值绝对值 $ \le10^8 $
 

题解

  • 裸的线段树扫描线。。。 $ yyh $ 说这道题 n 很小,不用扫描线用神奇做法也可以。。。
     

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 500
#define ll long long 
struct tree{ ll l,r,sum; }t[maxn<<3];
struct data{ ll x,y1,y2; int f; }p[maxn<<3];
int n,cases,lazy[maxn<<3];
ll ans,s[maxn<<3];
bool cmp(data a,data b){ return a.x<b.x; }
void pushup(int o){
	if(lazy[o]>0) t[o].sum=t[o].r-t[o].l;
	else t[o].sum=t[o<<1].sum+t[o<<1|1].sum;
}
void build(int o,int l,int r){
	t[o].l=s[l]; t[o].r=s[r];
	if(r-l<=1){ t[o].sum=0; return; }
	int mid=l+r>>1;
	build(o<<1,l,mid); build(o<<1|1,mid,r);
	pushup(o);
}
void updata(int o,ll y1,ll y2,int flag){
	if(t[o].l==y1&&t[o].r==y2){ lazy[o]+=flag; pushup(o); return; }
	if(t[o<<1].r>y1) updata(o<<1,y1,min(t[o<<1].r,y2),flag);
	if(t[o<<1|1].l<y2) updata(o<<1|1,max(t[o<<1|1].l,y1),y2,flag);
	pushup(o);
}
int main(){
	freopen("olddriver.in","r",stdin);
	freopen("olddriver.out","w",stdout); 
	scanf("%d",&n); 
	ans=0;
	ll x1,x2,y1,y2;
	for(int i=1;i<=n;++i){
		scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
		p[i].x=x1; p[i].y1=y1; p[i].y2=y2; p[i].f=1;
		p[i+n].x=x2; p[i+n].y1=y1; p[i+n].y2=y2; p[i+n].f=-1;
		s[i]=y1; s[i+n]=y2;
	}
	sort(s+1,s+1+2*n);
	sort(p+1,p+1+2*n,cmp);
	build(1,1,2*n);
	memset(lazy,0,sizeof(lazy));
	for(int i=1;i<=2*n;++i){
		ans+=(p[i].x-p[i-1].x)*t[1].sum;
		updata(1,p[i].y1,p[i].y2,p[i].f);
	}
	printf("%lld",ans);
	return 0;
}
  • 这是zkq的神奇做法我没拿到yyh的程序,但是zkq的神奇做法也A了,应该是一样的
#include<bits/stdc++.h>
using namespace std;
struct books
{
    int x1,y1,x2,y2;
}c[510];
bool b[510][510];
int x[510],y[510];
int rx[510],ry[510],tx,ty;
int n,cnt;
long long ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&c[i].x1,&c[i].y1,&c[i].x2,&c[i].y2);
        x[++cnt]=c[i].x1;
		y[cnt]=c[i].y1;
        x[++cnt]=c[i].x2;
		y[cnt]=c[i].y2;
    }
    sort(x+1,x+cnt+1);
    sort(y+1,y+cnt+1);
    for(int i=1;i<=cnt;i++)
    {
        if(i==1||x[i]!=x[i-1])rx[++tx]=x[i];
        if(i==1||y[i]!=y[i-1])ry[++ty]=y[i];
    }
    for(int i=1;i<=n;i++)
    {
        int X1,X2,Y1,Y2;
        int l=1,r=tx;
    	while(l<r)
    	{
    	    int mid=(l+r+1)>>1;
	        if(rx[mid]<=c[i].x1)l=mid;
	        else r=mid-1;
    	}
    	X1=l;
    	l=1,r=tx;
		while(l<r)
    	{
    	    int mid=(l+r+1)>>1;
	        if(rx[mid]<=c[i].x2)l=mid;
	        else r=mid-1;
    	}
    	X2=l; 
        l=1,r=ty;
	    while(l<r)
	    {
	        int mid=(l+r+1)>>1;
	        if(ry[mid]<=c[i].y1)l=mid;
	        else r=mid-1;
	    }
	    Y1=l;
		l=1,r=ty;
	    while(l<r)
	    {
	        int mid=(l+r+1)>>1;
	        if(ry[mid]<=c[i].y2)l=mid;
	        else r=mid-1;
	    }
	    Y2=l;
        for(int j=X1;j<X2;j++)
            for(int k=Y1;k<Y2;k++)
                b[j][k]=1;
    }
    for(int i=1;i<tx;i++)
        for(int j=1;j<ty;j++)
            if(b[i][j])ans+=1ll*(rx[i+1]-rx[i])*(ry[j+1]-ry[j]);
    printf("%lld",ans);
    return 0;
}
posted @ 2018-08-07 19:59  potrem  阅读(267)  评论(0编辑  收藏  举报