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)的赋值要处理好。

  • 相关阅读:
    mysql导出表的数据,在导入
    oracle数据迁移到mysql
    mybatis-使用generator反向数据库表并生成dao和mapping映射
    SQLserver单表数据导入导出
    java内省
    java反射
    springmvc文件上传
    Dubbo学习笔记8:Dubbo的集群容错与负载均衡策略
    Dubbo学习笔记7:Dubbo增强SPI与SPI中扩展点自动包装的实现原理
    Dubbo学习笔记6:Dubbo整体框架分析
  • 原文地址:https://www.cnblogs.com/last-diary/p/11454811.html
Copyright © 2011-2022 走看看