NOIp 0910 爆零记

时间:2023-03-09 07:27:43
NOIp 0910 爆零记

这套题是神犇chty出的。

刚拿到题的时候有点懵逼,因为按照一般的套路第一题都是一眼题,但是看到第一题后想了很多个算法和数据结构好像都不能很好的解决。然后就随手敲了个暴力去看T2。

嗯...文件名是bag这道题还真就是bag,听说是分组背包?背包现在我也就会个0/1了,所以怒上并查集优化相对关系。顺利AC

 //T2
 //by Cydiater
 //2016.9.10
 #include <iostream>
 #include <cstdio>
 #include <cstdlib>
 #include <cmath>
 #include <queue>
 #include <map>
 #include <cstring>
 #include <string>
 #include <algorithm>
 #include <queue>
 #include <iomanip>
 using namespace std;
 #define ll long long
 #define up(i,j,n)        for(int i=j;i<=n;i++)
 #define down(i,j,n)        for(int i=j;i>=n;i--)
 #define FILE "bag"
 ;
 const int oo=0x3f3f3f3f;
 inline int read(){
     ,f=;
     ;ch=getchar();}
     +ch-';ch=getchar();}
     return x*f;
 }
 ],Ans=,q[MAXN];
 struct _data{
     int v,group_id,w;
 }a[MAXN];
 namespace solution{
     int getf(int k){
         if(f[k]==k)return k;
         f[k]=getf(f[k]);
         return f[k];
     }
     inline void merge(int x,int y){f[getf(x)]=getf(y);}
     inline bool cmp(_data x,_data y){return x.group_id<y.group_id;}
     void init(){
         N=read();M=read();K=read();
         up(i,,N){
             a[i].v=read();
             a[i].w=read();
             f[i]=i;
         }
         up(i,,K){
             int x=read(),y=read();
             merge(x,y);
         }
         up(i,,N)a[i].group_id=getf(i);
         sort(a+,a+N+,cmp);
     }
     void DP(){
         a[].group_id=;
         up(i,,N){
             ].group_id){
                 head=;tail=;q[++tail]=i++;
                 ].group_id)q[++tail]=i++;i--;
             }
             down(k,M,)up(j,head,tail){
                 int id=q[j];
                 if(a[id].w+k<=M){
                     ans[a[id].w+k]=max(ans[a[id].w+k],ans[k]+a[id].v);
                     Ans=max(Ans,ans[a[id].w+k]);
                 }
             }
         }
     }
     void output(){
         cout<<Ans<<endl;
     }
 }
 int main(){
     freopen(FILE".in","r",stdin);
     freopen(FILE".out","w",stdout);
     //freopen("input.in","r",stdin);
     using namespace solution;
     init();
     DP();
     output();
     ;
 }

T2

然后扭过头去看T1了...看着题,开始想怎么优化线段树..想了五分钟,弃疗。正准备去看第三题,忽然想到貌似这个是莫队的模板题。敲了一下,不是很放心,拍了半小时,好像没什么问题。就交了。

 //test for bat
 //by Cydiater
 //2016.9.10
 #include <iostream>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 #include <string>
 #include <algorithm>
 #include <queue>
 #include <map>
 #include <iomanip>
 #include <cmath>
 #include <ctime>
 using namespace std;
 #define ll long long
 #define up(i,j,n)        for(int i=j;i<=n;i++)
 #define down(i,j,n)        for(int i=j;i>=n;i--)
 #define FILE "tower"
 ;
 const int oo=0x3f3f3f3f;
 inline int read(){
     ,f=;
     ;ch=getchar();}
     +ch-';ch=getchar();}
     return x*f;
 }
 ,head,tail;
 struct Query{
     int x,y,id,ans;
 }q[MAXN];
 namespace solution{//vio makes different
     inline bool cmp(Query x,Query y){return btBlock[x.y]==btBlock[y.y]?x.x<y.x:btBlock[x.y]<btBlock[y.y];}
     inline bool re_cmp(Query x,Query y){return x.id<y.id;}
     void init(){
         N=read();M=read();
         up(i,,N)a[i]=read();
         up(i,,M){
             int x=read(),y=read();
             if(y<x)swap(x,y);
             q[i].x=x;q[i].y=y;q[i].id=i;
         }
         tmp=sqrt(1.0*N);
         up(i,,N)btBlock[i]=(i/tmp)+;
         sort(q+,q+M+,cmp);
     }
     void push(int id,int tag){
         Count[a[id]]+=tag;
         &&Count[a[id]]==)ans++;
         &&Count[a[id]]==)ans--;
     }
     void MosAlg(){
         memset(Count,,sizeof(Count));
         head=;tail=;
         up(k,,M){
             int x=q[k].x,y=q[k].y;
             );
             );
             );
             );
             q[k].ans=ans;
         }
     }
     void output(){
         sort(q+,q+M+,re_cmp);
         up(i,,M)printf("%d\n",q[i].ans);
         //cout<<"Time has passed"<<1.0*clock()/1000<<"s!"<<endl;
     }
 }
 int main(){
     //freopen("input.in","r",stdin);
     //freopen("out1.out","w",stdout);
     freopen(FILE".in","r",stdin);
     freopen(FILE".out","w",stdout);
     using namespace solution;
     init();
     MosAlg();
     output();
     ;
 }

T1

然后考完试后有人给我说把所有可能的询问存下来就行了= =....我还能说些什么

然后就去看喜闻乐见的T3了。

一眼贪心,然后就很快速的想到了$O(NM)$的算法。这个$N$后的$M$是可优化的,其本质就是查找一个动态集合里$num$的后继,这不就是treap吗?

但是思考具体实现好像出了些问题,因为我的贪心排序是递增排序(实际上应该是递减排序,递减排序的话也就没有了下面所说的麻烦),而递增排序的话每次访问过的节点必定是$id$以后的节点,这就很不优雅了,我需要维护一个$node$和$v$的关系。

然后$v$还可以重复...

exm?

思考了半天怎么防止区间重复的删除,到了11:20,弃疗,敲暴力。

然后暴力就敲崩了。

这个是最后改好的:

 //OJ 1939
 //by Cydiater
 //2016.9.10
 #include <iostream>
 #include <cstdio>
 #include <cstring>
 #include <string>
 #include <algorithm>
 #include <queue>
 #include <map>
 #include <ctime>
 #include <cmath>
 #include <string>
 #include <iomanip>
 using namespace std;
 #define ll long long
 #define up(i,j,n)        for(int i=j;i<=n;i++)
 #define down(i,j,n)        for(int i=j;i>=n;i--)
 ;
 const ll oo=0x3f3f3f3f;
 inline ll read(){
     ,f=;
     ;ch=getchar();}
     +ch-';ch=getchar();}
     return x*f;
 }
 ,tol=,tmp;
 ll ans=;
 struct _data{
     int x,y;
 }a[MAXN],b[MAXN];
 struct tree{
     int leftt,rightt,v,siz,cnt,rnd;
 }t[MAXN];
 namespace solution{
     inline bool cmpfory(_data x,_data y){return x.y>y.y;}
     inline void updata(int k){t[k].siz=t[t[k].leftt].siz+t[t[k].rightt].siz+t[k].cnt;}
     void init(){
         N=read();M=read();
         up(i,,N){
             a[i].x=read();a[i].y=read();
         }
         up(i,,M){
             b[i].x=read();b[i].y=read();
         }
         sort(a+,a+N+,cmpfory);
         sort(b+,b+M+,cmpfory);
     }
     void lefturn(int &k){
         int tt=t[k].rightt;t[k].rightt=t[tt].leftt;t[tt].leftt=k;
         t[tt].siz=t[k].siz;updata(k);k=tt;
     }
     void righturn(int &k){
         int tt=t[k].leftt;t[k].leftt=t[tt].rightt;t[tt].rightt=k;
         t[tt].siz=t[k].siz;updata(k);k=tt;
     }
     void insert(int &k,int v){
         ){
             k=++tol;t[k].leftt=t[k].rightt=;
             t[k].rnd=rand();t[k].v=v;t[k].siz=t[k].cnt=;
             return;
         }
         t[k].siz++;
         if(t[k].v==v){
             t[k].cnt++;
             return;
         }
         if(v<t[k].v){
             insert(t[k].leftt,v);
             if(t[k].rnd>t[t[k].leftt].rnd)righturn(k);
         }else if(v>t[k].v){
             insert(t[k].rightt,v);
             if(t[k].rnd>t[t[k].rightt].rnd)lefturn(k);
         }
     }
     void nxt(int k,int v){
         )return;
         if(t[k].v>=v){
             tmp=t[k].v;
             nxt(t[k].leftt,v);
         }else nxt(t[k].rightt,v);
     }
     void del(int &k,int v){
         )return;
         if(v==t[k].v){
             ){
                 t[k].cnt--;
                 t[k].siz--;
                 return;
             }
             ){
                 k=t[k].leftt+t[k].rightt;
                 return;
             }
             if(t[t[k].leftt].rnd<t[t[k].rightt].rnd){
                 righturn(k);
                 del(k,v);
             }else{
                 lefturn(k);
                 del(k,v);
             }
         }
         else if(v<t[k].v){
             t[k].siz--;
             del(t[k].leftt,v);
         }else{
             t[k].siz--;
             del(t[k].rightt,v);
         }
     }
     void slove(){
         ;
         up(i,,N){
             while(b[j].y>=a[i].y&&j<=M)
                 insert(root,b[j++].x);
             tmp=-;
             nxt(root,a[i].x);ans+=tmp;
             ){
                 puts("-1");
                 exit();
             }
             del(root,tmp);
         }
     }
     void output(){
         cout<<ans<<endl;
     }
 }
 int main(){
     //freopen("input.in","r",stdin);
     using namespace solution;
     init();
     slove();
     output();
     ;
 }

T3

最后$100+100+0$滚粗。

小结:

还是应该提高自己的姿势水平,贪心这种东西太玄了。而且比赛也要多打,思路要放宽。对我们来说NOIp比的实际上已经是谁能AK了。