2016-浙江理工新生赛-部分题解

巴比伦花园

        link :http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4239

       对于新生还是比较难;

我是用 RMQ + 二分 写的; 因为  fi[i]  数组代表从i开始最长到哪里,因为要求最长,所以第一个一定是1, i 是单调的,fi 数组也是单调的,所以可以二分;二分找刚刚在区间的,完全在区间用RMQ 离线查询;


#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
 
using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MAXSIZE=1e6+5;
const double eps=0.0000000001;
void fre()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
}
#define memst(a,b) memset(a,b,sizeof(a))
#define fr(i,a,n) for(int i=a;i<n;i++)
 
 
const int MAXN=1e5+10;

int n,k,q;
LL input[MAXN];
int fi[MAXN];

struct RMQ
{
	int dp[MAXN][20];
	void init()
    {
	    for(int i=1;i<=n;i++) dp[i][0]=fi[i];
	    for(int i=1;i<20;i++) 
	    	for(int j=1;j<=n;j++)	
	    		if(j+(1<<i)-1<=n) dp[j][i]=max(dp[j][i-1],dp[j+(1<<(i-1))][i-1]);
    }
    int query(int l,int r)
    {
    	if(l>r) return -1;
    	if(l==r) return fi[l];
	    int _k=(int)log2(r-l+1);
	    return max(dp[l][_k],dp[r-(1<<_k)+1][_k]);
    }
}rmq;

int query(int l,int st)
{
	for(int i=l;i<=n;i++)
		if(input[i]<1+k*((LL)i-st)) return i-st;
	return n-st+1;
}
int findR(int L,int R,int& b)
{
	int l=1,r=n;
	while(1)
	{
		int mid=(l+r)>>1;
		if(fi[mid]+mid-1>=R&&fi[mid-1]+mid-2<R) 
		{
			b=mid-1;
			return R-max(L,mid)+1;
		}
		if(fi[mid]+mid-1>=R) r=mid;
		else l=mid+1;
	}
}
int findL(int L,int R,int& a)
{
	int l=1,r=n;
	while(1)
	{
		int mid=(l+r)>>1;
		if(mid<=L&&mid+1>L) 
		{
			a=mid+1;
			return min(R,mid+fi[mid]-1)-L+1;
		}
		if(mid<=L) l=mid+1;
		else r=mid;
	}
}
int main()
{
	int ncase;
	scanf("%d",&ncase);
	while(ncase--)
	{
		scanf("%d%d%d",&n,&k,&q);
		fi[0]=-INF;
		for(int i=1;i<=n;i++)
			scanf("%lld",&input[i]);
		for(int i=1;i<=n;i++)
			fi[i]=query(max(i-1+fi[i-1],i),i);
	    fi[n+1]=INF;
		rmq.init();
		while(q--)
		{
			int l,r,a,b;
			scanf("%d%d",&l,&r);
			int maxnum=max(findL(l,r,a),findR(l,r,b));
			printf("%d\n",max(rmq.query(a,b),maxnum));
		}
	}
	return 0;
}

/**************************************************/
/**             Copyright Notice                 **/
/**  writer: wurong                              **/
/**  school: nyist                               **/
/**  blog  : http://blog.csdn.net/wr_technology  **/
/**************************************************/


D  题也是同一种套路; RMQ + 二分

4241: 圣杯战争

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <time.h>

using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MAXSIZE=1e6+5;
const double eps=0.0000000001;
void fre()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
}
#define memst(a,b) memset(a,b,sizeof(a))
#define fr(i,a,n) for(int i=a;i<n;i++)


const int MAXN=2e5+10;

int n,m,q,total,ans;
LL atk[MAXN],presum[MAXN];
int ap[MAXN],pos[MAXN];
pair<int,int> seg[MAXN],Interval[MAXN];

struct RMQ
{
	int dp[MAXN][20];
	void init()
    {
	    for(int i=1;i<total;i++) dp[i][0]=Interval[i].second-Interval[i].first+1;
	    for(int i=1;i<20;i++)
	    	for(int j=1;j<total;j++)
	    		if(j+(1<<i)-1<total) dp[j][i]=max(dp[j][i-1],dp[j+(1<<(i-1))][i-1]);
    }
    int query(int l,int r)
    {
    	if(l>r) return 0;
	    int _k=(int)log2(r-l+1);
	    return max(dp[l][_k],dp[r-(1<<_k)+1][_k]);
    }
}rmq;
bool cmp(pair<int,int> a,pair<int,int> b)//按照 first 从小到大,first 一样的按照 second 的从大到小
{
    if(a.first!=b.first) return a.first<b.first;
    else return a.second>b.second;
}
bool cmp1(pair<int,int> a,int val)
{
    return a.first<val;
}
bool cmp2(pair<int,int> a,int val)
{
    return a.second<val;
}
int query(int l,int r)
{
    l=l^ans,r=r^ans;
    if(l>r) swap(l,r);
    l=max(1,l),r=min(n,r);
 //   printf("query %d %d\n",l,r);
    int fl,fr,maxnum;
    fl=lower_bound(Interval+1,Interval+total,l,cmp1)-Interval-1;
    fr=lower_bound(Interval+1,Interval+total,r,cmp2)-Interval;
  //
    int ans1=min(Interval[fl].second,r)-max(l,Interval[fl].first)+1;
    int ans2=min(r,Interval[fr].second)-max(l,Interval[fr].first)+1;
    if(fl>=total||fl<=0) ans1=-1;
    if(fr>=total||fr<=0) ans2=-1;
    maxnum=max(ans1,ans2);
   // printf("ans= %d %d %d\n",ans1,ans2,rmq.query(fl+1,fr-1));
    return max(rmq.query(fl+1,fr-1),maxnum);
}
void  debug(int k)
{
//    for(int i=0;i<k;i++)
//        printf("seg[%d] : %d %d\n",i,seg[i].first,seg[i].second);
//    printf("\n***********************************\n");
    printf("total=%d\n",total);
    for(int i=1;i<total;i++)
        printf("seg[%d] : %d %d\n",i,Interval[i].first,Interval[i].second);
    printf("\n***********************************\n");
}
LL getval(int l,int r)
{
    return presum[r]-presum[l-1];
}
int Lpos(int _pos,int _ap)
{
    int l=1,r=_pos;
    while(1)
    {
        int mid=(l+r)>>1;
        if((mid==1&&getval(mid,_pos)<=_ap)||(getval(mid,_pos)<=_ap&&getval(mid-1,_pos)>_ap)) return mid;
        if(getval(mid,_pos)<=_ap) r=mid;
        else l=mid+1;
    }
}
int Rpos(int _pos,int _ap)
{
    int l=_pos,r=n;
    while(1)
    {
        int mid=(l+r)>>1;
        if((mid==n&&getval(_pos,mid)<=_ap)||(getval(_pos,mid)<=_ap&&getval(_pos,mid+1)>_ap)) return mid;
        if(getval(_pos,mid)<=_ap) l=mid+1;
        else r=mid;
    }
}
int main()
{
	int ncase;
	scanf("%d",&ncase);
	while(ncase--)
	{
		scanf("%d%d%d",&n,&m,&q);
		presum[0]=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&atk[i]);
			presum[i]=atk[i]+presum[i-1];
		}
		for(int i=0;i<m;i++)
			scanf("%d",&pos[i]);
		for(int i=0;i<m;i++)
			scanf("%d",&ap[i]);
		int k=0;
        presum[n+1]=INF;
		for(int i=0;i<m;i++)
		{
			if(ap[i]<atk[pos[i]]) continue;
			seg[k].first=Lpos(pos[i],ap[i]),seg[k++].second=pos[i];
			seg[k].first=pos[i],seg[k++].second=Rpos(pos[i],ap[i]);
		}
		// OK;
		if(k==0)
        {
            int l,r;
            while(q--) scanf("%d%d",&l,&r),printf("0\n");
            continue;
        }
		sort(seg,seg+k,cmp);//OK;
		total=2;
		Interval[1]=seg[0];
		for(int i=1;i<k;i++)
            if(seg[i].second>Interval[total-1].second)
                Interval[total++]=seg[i];
        rmq.init();
        Interval[0].first=Interval[0].second=-1;
        Interval[total].first=Interval[total].second=INF;
        ans=0;
      //  debug(k);
        while(q--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%d\n",ans=query(l,r));
        }
	}
	return 0;
}

/**************************************************/
/**             Copyright Notice                 **/
/**  writer: wurong                              **/
/**  school: nyist                               **/
/**  blog  : http://blog.csdn.net/wr_technology  **/
/**************************************************/

 

4248: KI的目标

/*
如果 dis(a,b)>=val[a]-val[b] && dis[b,c]>=val[b]-val[c];
那么 dis(a,c)>=val[a]-val[c];
所以 只需要判断 val[现在的点]-val[下一个点]>边权值  如果真就不统计;
*/
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <time.h>

using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MAXSIZE=1e6+5;
const double eps=0.0000000001;
void fre()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
}
#define memst(a,b) memset(a,b,sizeof(a))
#define fr(i,a,n) for(int i=a;i<n;i++)



const int MAXN = 1000000+10;
struct Node
{
    int to,next,val;
}edge[MAXN<<1];
int first[MAXN],ntot;
void init()
{
    ntot=0;
    memset(first,-1,sizeof(first));
}
void addedge(int s,int t,int val)
{
    edge[ntot].to=t,edge[ntot].val=val;
    edge[ntot].next=first[s];
    first[s]=ntot++;
}
int val[MAXN];
int n;

int dfs (int o,int now)
{
    int res=1;
    for (int i=first[now],to,value; ~i; i=edge[i].next)
    {
        to=edge[i].to, value=edge[i].val;
        if (to==o) continue;
        if (val[now]-val[to]>value)  //val(v)<val(u)+path(u)-Path(v)  那么val(u)+path(u)取最大
        {
            continue;
        }
        res += dfs (now, to);
    }
    return res;
}

int main ()
{
    int ncase;
    scanf ("%d", &ncase);
    while(ncase--)
    {
        scanf ("%d", &n);
        init();
        for (int i=1,u,v,w; i<n; i++)
        {
            scanf ("%d%d%d", &u, &v, &w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        for (int i=1; i<=n; i++) scanf ("%d", val+i);
        printf ("%d\n", dfs (1, 1));
    }
    return 0;
}



/**************************************************/
/**             Copyright Notice                 **/
/**  writer: wurong                              **/
/**  school: nyist                               **/
/**  blog  : http://blog.csdn.net/wr_technology  **/
/**************************************************/





















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值