zoukankan      html  css  js  c++  java
  • Test 2018-07-20 二中集训

    Black Rock Shooter

    原题:SPOJ GSS3

    $ ightarrow $ 戳我进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
    ",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 (原题坐标和面积是带小数点的)

    $ ightarrow $ 戳我进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;
    }
    
  • 相关阅读:
    一轮项目冲刺——移山小分队(9)
    一轮项目冲刺——移山小分队(8)
    一轮冲刺项目——移山小分队(7)
    一轮项目冲刺——移山小分队(6)
    一轮项目冲刺——移山小分队(5)
    一轮项目冲刺——移山小分队(4)
    一轮项目冲刺——移山小分队(3)
    一轮项目冲刺——移山小分队(2)
    一轮项目冲刺——移山小分队(1)
    C# 记录循环消耗时间
  • 原文地址:https://www.cnblogs.com/PotremZ/p/Test20180720.html
Copyright © 2011-2022 走看看