zoukankan      html  css  js  c++  java
  • 选择客栈noip2011

    哈,没想到吧。今天居然有两篇(算什么,厕所读物吗

    选择客栈

    本题的更优解请跳转zt

    这题11年,刚改2day。

    对于30% 的数据,有 n ≤100;

    对于50% 的数据,有 n ≤1,000;

    对于100%的数据,有 2 ≤n ≤200,000,0<k ≤50,0≤p ≤100 , 0 ≤最低消费≤100。

    好的,直接枚举左边的客栈,枚举右边的客栈,再判断是否合法就OK了。

    数组开大一点还多过了luogu的一个点(垃圾数据

    #include<iostream>
    #include<cstdio>
    #include<string>
    #include<cstring>
    using namespace std;
    inline void in(int &p,char c=getchar())
    {
    	while(c<'0' or c>'9')
    		c=getchar();
    	p=0;
    	while(c>='0' and c<='9')
    		p=p*10+c-'0',c=getchar();
    }
    struct hotel
    {
    	int color;
    	int money;
    }h[1000001];
    long long ans;
    int main()
    {
    	int n,m,maxmoney;
    	in(n);in(m);in(maxmoney);
    	for(int i=1;i<=n;i++)
    		in(h[i].color),in(h[i].money);
    	for(int i=1;i<=n;i++)
    	{	
    		bool you=(h[i].money<=maxmoney);//这是“有”,不是“右”
    		for(int j=i+1;j<=n;j++)
    		{
    			if(h[j].money<=maxmoney)
    				you=1;
    			if(you and i!=j and h[i].color==h[j].color)
    				ans++;
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    

    看了题解,我受到启发。决定小题大做,用线段树

    toby_ztだらお:为什么要用线段树?

    对于两个客栈之间,只要有一个咖啡厅符合条件,那整段都符合条件,很有线段树的感觉。

    这题用线段树的话,只需要建树

    void build(int rt,int l,int r)
    {
    	if(l==r)
    	{
    		tree[rt]=di[l];
    		return ;
    	}
    	int m=(l+r)>>1;
    	build(rt<<1,l,m);
    	build(rt<<1|1,m+1,r);
    	tree[rt]=(tree[rt<<1] or tree[rt<<1|1]);
    }
    

    和查询

    bool getans(int rt,int L,int R,int l,int r)
    {
    	if(L<=l and R>=r)
    		return tree[rt];
    	int m=(l+r)>>1;
    	bool aans=0;//我外面定义一个计答案的ans,为了程序的严谨性,嗯变量名丑一点也是可以原谅的
    	if(L<=m and !aans)
    		aans=getans(rt<<1,L,R,l,m);
    	if(R>m and !aans)//!aans的目的是减少不必要的查询。若已经有左子树ok,右子树什么样已经不重要了
    		aans=getans(rt<<1|1,L,R,m+1,r);
    	return aans;
    }
    

    两种操作。

    那怎么枚举求的区间呢?或者说,怎么枚举两个人住的两家酒店?

    为了减少枚举量,我们可以按颜色(色调)枚举。

    使用vector <int> 存每种颜色的酒店。

    输入的时候就顺手预处理一下:

    vector <int> c[52];//0-50的话,最多有51种,所以开52就够啦
    ...
    for(int i=1;i<=n;i++)
    {
    	int x,y;
    	in(x);in(y);//in(int &p)就是读入优化
    	c[x].push_back(i);
    	if(y<=maxm)//maxm是两个人最高的消费
    		di[i]=1;//标记一下,给一会建树用
    }
    

    枚举的时候就是这样:

    for(int i=0;i<m;i++)
    	for(unsigned int j=0;j<c[i].size()-1;j++)//注意<size()-1
    		for(unsigned int k=j+1;k<c[i].size();k++)
    		{
    			bool flag=0;//如果这c[i][j]~~c[i][k]这段ok的话,那后面的也都ok啦
    			flag=getans(1,c[i][j],c[i][k],1,n);
    			if(flag)
    			{
    				ans+=c[i].size()-k;//大家随便画个图体会一下为什么是size()-k
    				break;
    			}
    		}
    
    

    最后输出ans。

    ans需不需要开long long我并没有测试,不过还是开了保险。

    完整版:

    #include<iostream>
    #include<cstdio>
    #include<string>
    #include<cstring>
    #include<vector>
    using namespace std;
    inline void in(int &p,char c=getchar())
    {
    	while(c<'0' or c>'9')
    		c=getchar();
    	p=0;
    	while(c>='0' and c<='9')
    		p=p*10+c-'0',c=getchar();
    }
    vector <int> c[52];
    bool tree[200001<<2],di[200001];
    long long ans;
    void build(int rt,int l,int r)
    {
    	if(l==r)
    	{
    		tree[rt]=di[l];
    		return ;
    	}
    	int m=(l+r)>>1;
    	build(rt<<1,l,m);
    	build(rt<<1|1,m+1,r);
    	tree[rt]=(tree[rt<<1] or tree[rt<<1|1]);
    }
    bool getans(int rt,int L,int R,int l,int r)
    {
    	if(L<=l and R>=r)
    		return tree[rt];
    	int m=(l+r)>>1;
    	bool aans=0;
    	if(L<=m and !aans)
    		aans=getans(rt<<1,L,R,l,m);
    	if(R>m and !aans)
    		aans=getans(rt<<1|1,L,R,m+1,r);
    	return aans;
    }
    int main()
    {
    	int n,m,maxm;
    	in(n);in(m);in(maxm);
    	for(int i=1;i<=n;i++)
    	{
    		int x,y;
    		in(x);in(y);
    		c[x].push_back(i);
    		if(y<=maxm)
    			di[i]=1;
    	}
    	build(1,1,n);
    	for(int i=0;i<m;i++)
    		for(unsigned int j=0;j<c[i].size()-1;j++)
    			for(unsigned int k=j+1;k<c[i].size();k++)
    			{
    				bool flag=0;
    				flag=getans(1,c[i][j],c[i][k],1,n);
    				if(flag)
    				{
    					ans+=c[i].size()-k;
    					break;
    				}
    			}
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    NPOI开发手记
    jQuery.form开发手记
    jQuery.Flot开发手记
    node.js初探
    Linux私房菜阅读笔记
    c#实现常用排序算法
    Excel自定义函数开发手记
    浅谈知识管理
    Git学习手记
    c# 屏蔽快捷键
  • 原文地址:https://www.cnblogs.com/syhien/p/7754997.html
Copyright © 2011-2022 走看看