由于考试考得不太好 一个寒假没碰过笔也没写作业233能考好才怪。
当然 也不是坏到了极点。当然还可以坚持像以前一样来机房 写一些有意思的题目了!
早就想A那道题目了,看到qy dalao 去写了我想我也能写。
对于这道题目 贪心肯定是不行的吧,不知道从哪贪 30分。
裸的n^2 dp 那么就可以到手了。 f[i]表示 第i个磁带合法的最小代价
f[i]=min(f[i],f[j]+abs(a[j+1]-(i-j-1)));这样得到了30分 很容易的一个n^2 算法dp
然后瞄着 70分考虑优化,花费了我3个小时也只想到了 去绝对值。
设 k=i-i; f[i]=min{f[j]+a[j+1]+j-k}; 当且仅当 a[j+1]+j-k>=0
或者 f[i]=min(f[j]+k-a[j+1]-j); 当且仅当 a[j+1]+j-k<=0
我们发现有两个决策集合 这个斜率优化? 没什么用
单调队列也不行啊 因为k不具单调性 四边形不等式?(去一边区间dp
只能是数据结构优化了,树状数组?线段树?亦或者 权值线段树?
感觉都不太行啊,观察线段树的话我开两个 然后以什么为下标呢 a[j+1]+j
好像是可以很大很大的 但是可以离散复杂度稍微高一点且非常不好写。
qy dalao倒是交给我了一种方法,倒序dp发现很容易解决这个问题,且维护很好维护。
也很好写,当然我自己也是经过严密的思考(旷了早读,列了一堆式子
倒序dp:f[i]表示 第后i个磁带合法的最小代价 f[i]=min(f[i],abs(a[i]-j+1+i)+f[j])
设 k=a[i]+1+i f[i]=min{abs(k-j)+f[j]}那么这个问题如下:
分类讨论: 当 k-j>=0 时我们需要寻找 k~n 这个决策集合中最小的 f[j]-j ;
当k-j<=0 时我们需要寻找 1~k 这个决策集合中最小的 f[j]+j;
怎么寻找呢 开 multiset? 不太行 因为我们还要维护下标(不用离散 好开心好开心。
开两个线段树吧,维护一个区间最小值即可。此题结束。
另外值得一提的是这道题卡常 把我正确率都卡下去了QAQ
真的是丧心病狂的卡常 我最后把常数都卡到最小了 还是T 1一点。
无奈我使出了 把两个线段树当成一个线段树用减小近乎一倍的常数A掉了这道题呢!
//#include<bits/stdc++.h> #include<iostream> #include<iomanip> #include<cctype> #include<utility> #include<queue> #include<stack> #include<deque> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<ctime> #include<set> #include<bitset> #include<map> #include<cmath> #include<vector> #include<cstdlib> #define INF 2147483646 #define INF1 168430090 #define ll long long #define l(x) s[x].l #define r(x) s[x].r #define v(x) s[x].v #define R register using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } void put(int x) { x<0?putchar('-'),x=-x:0; int num=0;char ch[50]; while(x)ch[++num]=x%10+'0',x/=10; num==0?putchar('0'):0; while(num)putchar(ch[num--]); putchar(' ');return; } //考虑dp f[i]表示 第i个磁带合法的最小代价 //显然 f[i]=min(f[i],abs(a[i]-j+1+i)+f[j]) //设 k=a[i]+1+i f[i]=min{abs(k-j)+f[j]} const int MAXN=1000002; int n; int f[MAXN],a[MAXN]; inline int min(int x,int y) { return x>y?y:x; } struct wy { int l,r; int v; }t[MAXN<<2];//k>=j 的决策区间 struct wy1//k<=j 的决策区间 { int l,r; int v; }s[MAXN<<2]; inline void build(int p,int l,int r) { t[p].l=l,t[p].r=r; l(p)=l;r(p)=r; if(l==r) { if(l==n)t[p].v=-n,v(p)=n; else t[p].v=INF,v(p)=INF; return; } int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); t[p].v=min(t[p<<1].v,t[p<<1|1].v); v(p)=min(v(p<<1),v(p<<1|1)); } inline void change(int p,int l,int r,int d,int dd) { if(l<=t[p].l&&r>=t[p].r){t[p].v=d;v(p)=dd;return;} int mid=(t[p].l+t[p].r)>>1; if(l<=mid)change(p<<1,l,r,d,dd); if(r>mid)change(p<<1|1,l,r,d,dd); t[p].v=min(t[p<<1].v,t[p<<1|1].v); v(p)=min(v(p<<1),v(p<<1|1)); return; } inline int ask(int p,int l,int r) { if(l<=t[p].l&&r>=t[p].r)return t[p].v; int mid=(t[p].l+t[p].r)>>1; int cnt=INF; if(l<=mid)cnt=min(cnt,ask(p<<1,l,r)); if(r>mid)cnt=min(cnt,ask(p<<1|1,l,r)); return cnt; } inline int ask1(int p,int l,int r) { if(l<=l(p)&&r>=r(p))return v(p); int mid=(l(p)+r(p))>>1; int cnt=INF; if(l<=mid)cnt=min(cnt,ask1(p<<1,l,r)); if(r>mid)cnt=min(cnt,ask1(p<<1|1,l,r)); return cnt; } int main() { //freopen("1.in","r",stdin); n=read(); for(R int i=1;i<=n;++i)a[i]=read(),f[i]=INF;; n++;build(1,1,n); for(R int i=n-1;i>=1;--i) { R int k=a[i]+i+1; f[i]=min(f[i],ask(1,1,k>n?n:k)+k); if(k<=n)f[i]=min(f[i],ask1(1,k,n)-k); change(1,i,i,f[i]-i,f[i]+i); } put(f[1]); return 0; }
时不可兮骤得,聊逍遥兮容与!