zoukankan      html  css  js  c++  java
  • luogu P1311 选择客栈 题解

    (luogu) P1311 选择客栈 题解

    题目链接

    看到这道题目首先很茫然,一看统计方案数,肯定要什么数论或者数学知识吧,然后就打了个暴力,发现答案不对。于是就看了一下样例解释,发现统计方案数只需要选客栈的方案数,不需要管咖啡厅的方案数。然后改了改,交了上去,成功拿了(60)还多拿了10分

    #include<iostream>
    #include<climits>
    #include<cstdio>
    #define ll long long
    using namespace std;
    const int N=1e3+100;
    int n,k,p;
    int color[N],cost[N];
    int minn[N][N];
    ll ans;
    inline void pre()
    {
    	for (int i=1;i<=n;i++)
    	{
    		int minx=INT_MAX;
    		for (int j=i;j<=n;j++)
    		{
    			minx=min(minx,cost[j]);
    			minn[i][j]=minx;
    		}
    	}
    	return ;
    }
    int main()
    {
    	scanf("%d%d%d",&n,&k,&p);
    	for (int i=1;i<=n;i++)
    	scanf("%d%d",color+i,cost+i);
    	pre();
    	for (int i=1;i<=n;i++)
    	for (int j=i+1;j<=n;j++)
    	if (color[i]==color[j]&&minn[i][j]<=p)
    	ans++;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    教训:写一些函数或变量一定要看头文件,还是万能头好用

    发现如果题意是这样,这道题就比较简单,对于([l,r])只需要查询区间最小值是否满足就可以了。然后就想到了(ST)表,其实对于每一个固定的(l)(r)是否合法是满足单调性的,如果([l,r])合法,([l,[r,n]])就也一定合法。所以我们就可以二分出最小的(r),然后用后缀和或前缀和维护([r,n])一共有多少合法解,累加就是答案。

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=2e5+100;
    int f[21][N],color[N],sum[N][52];
    int n,k,p;
    ll ans;
    inline void RMQ()
    {
    	for (int j=1;(1<<j)<=n;j++)
    	for (int i=1;i+(1<<j)-1<=n;i++)
    	f[j][i]=min(f[j-1][i],f[j-1][i+(1<<(j-1))]);
    	return ;
    }
    inline int query(int l,int r)
    {
    	int k=log2(r-l+1);
    	return min(f[k][l],f[k][r-(1<<k)+1]);
    }
    inline int midfind(int x)
    {
    	int l=x+1,r=n,mid=(l+r)>>1,ans=n+1;
    	while (l<=r)
    	{
    		if (query(x,mid)<=p)
    		{
    			ans=mid;
    			r=mid-1;
    		}
    		else l=mid+1;
    		mid=(l+r)>>1;
    	}
    	return ans;
    }
    int main()
    {
    	scanf("%d%d%d",&n,&k,&p);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d%d",&color[i],&f[0][i]);
    		color[i]++;
    		for (int j=1;j<=51;j++)
    		if (j==color[i]) sum[i][j]=sum[i-1][j]+1;
    		else sum[i][j]=sum[i-1][j];
    	}
    	RMQ();
    	for (int i=1;i<=n-1;i++)
    	{
    		int now=midfind(i)-1;
    		ans+=sum[n][color[i]]-sum[now][color[i]];
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    教训:二分开始的([l,r])一定要确定好,(ans)的实际意义也要确定好,二分到(r)和无合法解(ans)的赋值要处理好。

  • 相关阅读:
    C++虚函数机制(转)
    C/C++中extern关键字详解(转)
    (转)Javascript定义类(class)的三种方法
    使用HtmlAgilityPack实现对网页内容的抓取
    (转)Lucene Document getBoost(float) 和 setBoost(float)
    (转)Ajax中Get请求与Post请求的区别
    (转)Lucene.net实现自定义排序
    Lucene.net基本功能核心代码
    (转)使用Lucene.Net实现全文检索
    C#将html table 导出成excel
  • 原文地址:https://www.cnblogs.com/last-diary/p/11454811.html
Copyright © 2011-2022 走看看