众所周知非完美算法的重要性。
然而不要看错题更重要
昨天的二试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);
}
}