• [CSP-S模拟测试]:爬(贪心)


    题目传送门(内部题134)


    输入格式

      第一行两个数$N,L$。
      接下来$N$行每行两个数$A_i,B_i$。
      接下来$N$行每行一个整数$C_i$。


    输出格式

      一行一个整数表示答案,无解输出$-1$。


    样例

    样例输入1:

    3 9
    6 3
    5 2
    3 1
    2
    2
    2

    样例输出1:

    2

    样例输入2:

    5 20
    3 2
    4 2
    6 3
    8 4
    10 5
    4
    2
    3
    4
    5

    样例输出2:

    -1


    数据范围与提示

      对于$40\%$的数据,$Nleqslant 1,000$;
      对于额外$20\%$的数据,$B_i=0$;
      对于额外$20\%$的数据,$C_i=0$;
      对于$100\%$的数据,$nleqslant 10^5,0leqslant A_i,B_i,C_ileqslant 10^9$。


    题解

    瞎打都能过的题……

    考场打了个假贪心$A$掉了,然而打部分分的$KX$表示不服(因为数据中没有给部分分),于是他就跟教练要求要出数据,于是……

    上面的$KX$有他博客的链接,欢迎大家消费$+$吐槽。

    考场上的贪心实际上已经很接近正解了。

    首先,按$A_i-B_i$排序,在爬不上去的情况下一定是优先选择$A_i-B_i$最大的。

    然后发现其实有的时候可以用一个$A_i$很大的“冲”上去,所以开一个大根堆就好了。

    但是还有一个情况,我们可以用一些$A_i-B_i$比较小的“积蓄能量”,然后用一个$A_i-B_i$较大但是$A_i$更大的“冲”上去。

    然后发现只与最后一个有关,所以可以只考虑最后一个选什么,用倍增思想维护即可。

    时间复杂度:$Theta(nlog n)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct rec{int A,B,delta;}e[100001];
    int N;
    long long L;
    long long C[100001],S[100001],F[20][100001];
    int lg[100001];
    int limits;
    bool vis[100001];
    int ans=0x3f3f3f3f;
    bool cmp(rec a,rec b){return a.delta>b.delta;}
    int cal(int l,int r){return min(F[lg[r-l+1]][l],F[lg[r-l+1]][r-(1<<lg[r-l+1])+1]);}
    int main()
    {
    	scanf("%d%lld",&N,&L);vis[0]=1;
    	for(int i=2;i<=N;i++)lg[i]=lg[i>>1]+1;
    	for(int i=1;i<=N;i++)
    	{
    		scanf("%d%d",&e[i].A,&e[i].B);
    		e[i].delta=e[i].A-e[i].B;
    	}
    	sort(e+1,e+N+1,cmp);limits=N;
    	for(int i=1;i<=N;i++)if(e[i].delta<0){limits=i-1;break;}
    	for(int i=1;i<=N;i++)
    	{
    		scanf("%d",&C[i]);
    		C[i]+=C[i-1];
    		S[i]=S[i-1]+e[i].delta;
    		F[0][i]=S[i]+e[i].delta-C[i];
    		if(vis[i-1]&&C[i]<S[i])vis[i]=1;
    	}
    	for(int i=1;i<=lg[N];i++)
    		for(int j=1,s=(1<<(i-1));j<=N-(1<<j)+1;j++)
    			F[i][j]=min(F[i-1][j],F[i-1][j+s]);
    	long long now;
    	int pos;
    	for(int i=1;i<N;i++)
    	{
    		now=L+e[i].delta-e[i].A;
    		pos=lower_bound(S+1,S+limits+1,now)-S;
    		if(pos==limits+1)continue;
    		if(vis[i-1]&&pos>i)
    			if(cal(i,pos)>e[i].delta)
    				ans=min(ans,pos);
    	}
    	for(int i=N,mx=0;i>=0;i--)
    	{
    		if(vis[i]&&S[i]+mx>=L)
    			ans=min(ans,i+1);
    		mx=max(mx,e[i].A);
    	}
    	if(ans==0x3f3f3f3f)puts("-1");
    	else printf("%d
    ",ans);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    ASP.NET MVC 3: Razor中的@:和语法
    telerik 值得学习 web mvc 桌面 控件大全
    Android 基于google Zxing实现对手机中的二维码进行扫描
    Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果
    SQL聚集索引和非聚集索引的区别
    SQL Server的聚集索引和非聚集索引
    请教一个Jquery ligerui 框架的小问题
    学习如何用VS2010创建ocx控件
    nginx-rtmp-module--------------WIKI
    rtmp一些状态信息详解-as连接FMS服务器报错状态汇总~~
  • 原文地址:https://www.cnblogs.com/wzc521/p/11824354.html
Copyright © 2020-2023  润新知