一次非常神奇的考試,考完試以后看着T2的0pts突然笑死我自己
太智障了這什么神奇的題意理解錯誤23333
T1一眼分類討論,兩眼二分,覺得分類討論有點玄學但是出題人八成不會卡【何】,然后本着對二分的恐懼打了玄學
關於T2,我沒了 豹笑 我沒想到一只鳥可能被打兩槍你敢信
T3?今天有T3?
T1:
正解是顯而易見的二分。然而我比較懶,又經常在二分上炸掉【寫得比較丑】,而且第一眼其實並不是二分。
如果k最后小於1,那么相對於原來1個單位時間的移動來說,肯定這種上下移動的步數越多越好。先dfs一次,跑出從起點到終點上下移動步數最多的最短路,然后計算出對應的k。如果這個k解出來大於1,就再跑一次使左右移動步數最多的最短路,再次解出k。這樣可以保證選取這個k的同時,跑的一定是最短路。
其實總是隱約不太放心,感覺可能有鍋XD然而最后A了

#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; int n,m,sx,sy,tx,ty; int a[110][110],vis[110][110]; int h[4]={0,-1,0,1}; int l[4]={-1,0,1,0}; double s; struct node{ int x,y,tmp,dis; bool operator < (const node a) const { return tmp < a.tmp; } }; priority_queue<pair<int,node> >q; node dfs1(){ node u; u.x=sx,u.y=sy,u.tmp=0; q.push(make_pair(0,u)); while(!q.empty()){ while(q.size()&&vis[q.top().second.x][q.top().second.y])q.pop(); if(!q.size())break; int d=-q.top().first; node x=q.top().second; q.pop(); vis[x.x][x.y]=1; if(x.x==tx&&x.y==ty){ x.dis=d; return x; } for(int i=0;i<4;i++){ node y=x; y.x+=h[i],y.y+=l[i]; if(y.x>0&&y.x<=n&&y.y>0&&y.y<=m&&!a[y.x][y.y]){ if(i==1||i==3)y.tmp++; q.push(make_pair(-(d+1),y)); } } } } node dfs2(){ node u; u.x=sx,u.y=sy,u.tmp=0; while(!q.empty())q.pop(); memset(vis,0,sizeof(vis)); q.push(make_pair(0,u)); while(!q.empty()){ while(q.size()&&vis[q.top().second.x][q.top().second.y])q.pop(); if(!q.size())break; int d=-q.top().first; node x=q.top().second; q.pop(); vis[x.x][x.y]=1; if(x.x==tx&&x.y==ty){ x.dis=d; return x; } for(int i=0;i<4;i++){ node y=x; y.x+=h[i],y.y+=l[i]; if(y.x>0&&y.x<=n&&y.y>0&&y.y<=m&&!a[y.x][y.y]){ if(i==0||i==2)y.tmp++; q.push(make_pair(-(d+1),y)); } } } } int main() { scanf("%d%d",&n,&m); scanf("%d%d%d%d",&sx,&sy,&tx,&ty); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); } } scanf("%lf",&s); node b=dfs1(); double k=(1.0*s-1.0*b.dis+1.0*b.tmp)/(1.0*b.tmp);//tmp上下,dis-tmp左右 if(k<1)printf("%.3lf",k); else{ b=dfs2(); k=(1.0*s-1.0*b.tmp)/(1.0*(b.dis-b.tmp));//tmp左右,dis-tmp上下 printf("%.3lf",k); } return 0; }
T2:
什么?一只鳥有可能被打兩次……?是你R光速換彈還是我鯤化而為鵬……?
咳咳,不是不是,其實真的挺智障的,居然沒想到一只鳥所占的區間可能會長於換彈時間…老實說,考試的時候還是不太認真XD
發現一只鳥可能被打兩次以后,就要考慮重復的問題。把區間排序以后扔進隊列可以解決當前時間的區間覆蓋數目。
然后要從0~i-k選出一個去掉重復個數的f[j]進行轉移。選取最大的f值以及對重復個數的修改都可以利用線段樹完成。線段樹以時間為下標,儲存f[i]-(同時覆蓋i與當前時間的區間個數)。維護方式是,根據前面的隊列,當有新的區間的l覆蓋了當前時間而入隊時,使得l到r這一段區間-1,含義是這一段對於當前時間多了一個重復區間。而一段隊列里的區間的r小於當前時間出隊時,再把對應的l到r這一段+1,這一個區間不再重復了。
從0掃到max,max是最大的r。ans即為最大的(根據當前時間i查詢的線段樹中0->i-k中最大值+當前時間點的區間覆蓋數量【隊列size】)。
要注意各處l或r小於0的區間的處理。

#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; int n,k,top=1,ans,sum,maxx; struct node{ int l,r; bool operator < (const node x)const{ return l==x.l?r<x.r:l<x.l; } }a[200010]; priority_queue<pair<int,node> >q; struct tree{ int l,r,maxx,tag; }b[500010*8]; void pushdown(int p){ if(b[p].tag){ b[p*2].tag+=b[p].tag; b[p*2].maxx+=b[p].tag; b[p*2+1].tag+=b[p].tag; b[p*2+1].maxx+=b[p].tag; b[p].tag=0; } } void pushup(int p){ b[p].maxx=max(b[p*2].maxx,b[p*2+1].maxx); } void build(int p,int l,int r){ b[p].l=l,b[p].r=r; b[p].maxx=b[p].tag=0; if(l==r)return; int mid=(l+r)/2; build(p*2,l,mid); build(p*2+1,mid+1,r); } void change(int p,int l,int r,int y){ if(l<=b[p].l&&b[p].r<=r){ b[p].maxx+=y; b[p].tag+=y; return; } pushdown(p); int mid=(b[p].l+b[p].r)/2; if(l<=mid)change(p*2,l,r,y); if(r>mid)change(p*2+1,l,r,y); pushup(p); } void update(int p,int l,int r,int y){ if(l<=b[p].l&&b[p].r<=r){ b[p].maxx=y; b[p].tag=0; return; } pushdown(p); int mid=(b[p].l+b[p].r)/2; if(l<=mid)update(p*2,l,r,y); if(r>mid)update(p*2+1,l,r,y); pushup(p); } int ask(int p,int l,int r){ if(l<=b[p].l&&b[p].r<=r){ return b[p].maxx; } pushdown(p); int mid=(b[p].l+b[p].r)/2; int val=0; if(l<=mid)val=max(val,ask(p*2,l,r)); if(r>mid)val=max(val,ask(p*2+1,l,r)); pushup(p); return val; } int main(){ scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d%d",&a[i].l,&a[i].r); maxx=max(maxx,a[i].r); } sort(a+1,a+n+1); build(1,0,maxx); for(int i=0;i<=maxx;i++){ while(a[top].l<=i&&top<=n){ if(a[top].r<0){ top++; continue; } q.push(make_pair(-a[top].r,a[top])); change(1,max(0,a[top].l),a[top].r,-1); top++; } while(q.top().second.r<i&&q.size()){ change(1,max(0,q.top().second.l),q.top().second.r,+1); q.pop(); } if(i>=k)sum=ask(1,0,i-k); update(1,i,i,sum); ans=max(ans,sum+(int)q.size()); } printf("%d\n",ans); return 0; }
蠢出一定程度了…線段樹寫錯+隊列沒考慮l的入隊順序不一定是r的出隊順序於是沒寫優先隊列…改了挺長時間的
T3:
咕 咕咕咕 咕咕咕咕【飛了】
今天發現各處彌漫着稍許頹廢的氣息
可能是 秋天到了吧【何】