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;
    }
    
  • 相关阅读:
    hdu 1017 A Mathematical Curiosity 解题报告
    hdu 2069 Coin Change 解题报告
    hut 1574 组合问题 解题报告
    hdu 2111 Saving HDU 解题报
    hut 1054 Jesse's Code 解题报告
    hdu1131 Count the Trees解题报告
    hdu 2159 FATE 解题报告
    hdu 1879 继续畅通工程 解题报告
    oracle的系统和对象权限
    oracle 自定义函数 返回一个表类型
  • 原文地址:https://www.cnblogs.com/PotremZ/p/Test20180720.html
Copyright © 2011-2022 走看看