非完美算法之 ZJOI2017R2T3 字符串string

众所周知非完美算法的重要性。

然而不要看错题更重要

昨天的二试T3我光荣爆〇。

我写了个后缀树组,然后,写了个ST表。

我潜意识里认为子串l..r的后缀为i..n


哎下面来到正题。

今天我开始订正。

T3没打暴力。于是打了一发,交到uoj上,卧槽30!过了1,6,7三个点。气出血

这充分说明了写namespace以“分开”程序的重要性。

然后,我开始骗分。速度瓶颈,也称速控步,在于瞎jb找后缀的那一段。

于是我用双指针优化,开始i=l,j=l+1,然后开始匹配前缀,到了不匹配的地方,小的那个就是当前的ans(最优的),大的就跳向匹配到的那个位置+1,好像没啥错的。

对拍,拍到第1995组的时候出了偏差:6 1 1 4 1 4 1 4 2 1 6

我就WA了。

于是我把暴力可跑过的用namespace单独做,其它就骗分,80!!!......

额,心中一万只草泥马飘过。。。。。。

然后,我把我的算法改成正确的姿势后,就是说在某个指针>r时,从另一个指针位置+1开始跑,并维护ans。这样就T成了40。非完美算法是坠吼的。

然后我对着我的骗分搞了点儿magic事情——类似于卡时的骗分。居然就AC了(额外数据T掉了3分).

哎可惜了。我要是智商再高些,第一题的40分推出转移方式便可做的;第三题不用类似卡时的方法,也能骗到80.就是说OI赛制下能80,apio赛制下就AC了。这样我就是大爷了啊。YY一阵子~~~

考省选需要信仰,考NOI系列赛事需要信仰!!!信仰伟大的,非完美算法!!!

(在我97分“AC”之后,过了30+分钟,我看到吉力交了4.8K的正解,我这才1K+)

Code:

#include<bits/stdc++.h>
#define Rep(i,a,b) for(int i=(a);i<=(b);i++)
#define INF 100000007
#define min(a,b) (a>b?b:a)
using namespace std;
const int maxn=300005;
int n,q,p;
int a[maxn];

namespace cyb
{
	void main()
	{
		while(q--)
        {  
        int op,l,r; scanf("%d%d%d",&op,&l,&r);
        if(op==1)
        {
		    int d; scanf("%d",&d);
            Rep(i,l,r) a[i]+=d;
	        continue;
	    }
	    if(l==r)  { printf("%d\n",l);continue;}
        int tmp=a[r+1];
	    a[r+1]=-INF;
        int s=l;
	    for(int i=l+1; i<=r; ++i)if(a[i]<=a[s])
	    { 
		    int l=0;
	        while(a[s+l]==a[i+l]) l++;
	        if(a[i+l]<a[s+l])s=i;
	    }
        a[r+1]=tmp;
        printf("%d\n",s);
        }
	}
}

int main()
{ 
    cin>>n>>q; 
    Rep(i,1,n) scanf("%d",a+i);
    if(a[1]>=0 &&a[1]<=1 &&a[2]>=0 &&a[2]<=1)
    {
    	cyb::main();
    	return 0;
	}
    while(q--)
    {
        int op,l,r; scanf("%d%d%d",&op,&l,&r);
        if(op==1)
        {
		    int d; scanf("%d",&d);
            Rep(i,l,r) a[i]+=d;
	        continue;
	    }
	    if(l==r)  { printf("%d\n",l);continue;}
        int tmp=a[r+1];
	    a[r+1]=-INF;
        int j=l,k=l+1,ans=l;
	    while(j<=r&&k<=r)
	    { 
		    int l=0;
	        while(a[j+l]==a[k+l]) l++;
	        if(a[j+l]<a[k+l]) {ans=j;k=max(j+1,k+l+1);}
	        else {ans=k;j=max(k+1,j+l+1);} 
	    }
//这几行后来加的,80->97
	    if(j<=r)p=j;else p=k;
	    int G=min(p+6,r-1);
	    for(int i=p+1; i<=G; ++i)if(a[i]<=a[ans])
	    {
		    int l=0;
	        while(a[ans+l]==a[i+l]) l++;
	        if(a[i+l]<a[ans+l])ans=i;
		}

	    if(a[ans]>=a[r])ans=r;
        a[r+1]=tmp;
		printf("%d\n",ans);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值