noip模擬測試23
阿新 • • 發佈:2021-07-25
考試總結:這次考試,成績和自己的預估分數差距有點大,問題主要是出在了第一題上,我當時讀完題,就想到了線段樹,很快就碼完了,但是我當時沒有想到的兩個關鍵問題是:1.沒有想到離散化 2.對於異或的情況沒有分類討論,導致我第一題爆零,其他的題還好,基本上拿到了自己預估的分數。這次考試的教訓就是對於自己認為想到的正解多想想一些細節問題,不能想到啥就打啥。
T1 聯
思路:很顯然,一道線段樹裸題,我的演算法是記錄每個區間的1的數量之和,最後查詢的時候只需要按照先左後右的順序查詢當前區間裡1的數量和區間長度的大小即可,但是注意對於異或的操作進行分類討論,具體實現見程式碼:
#include<bits/stdc++.h> #define int long long #define re register int #define ii inline int #define iv inline void #define lc (rt<<1) #define rc (rt<<1|1) #define mid ((l+r)>>1) using namespace std; const int N=1e7+10; const int M=1e6+10; int m,ty,ul,ur,cnt; int lsh[M]; vector<int> v[N]; struct CUN { int sum,lazy; }use[N<<2]; struct Segment_tree { iv pp(int rt) { use[rt].sum=use[lc].sum+use[rc].sum; } iv pd(int rt,int l,int r) { if(use[rt].lazy) { if(use[rt].lazy==1) { use[lc].lazy=use[rc].lazy=use[rt].lazy; use[lc].sum=mid-l+1; use[rc].sum=r-mid; } else if(use[rt].lazy==2) { use[lc].lazy=use[rc].lazy=use[rt].lazy; use[lc].sum=0; use[rc].sum=0; } else { if(use[lc].lazy==1) { use[lc].lazy=2; use[lc].sum=0; } else if(use[lc].lazy==2) { use[lc].lazy=1; use[lc].sum=mid-l+1; } else if(use[lc].lazy==3) { use[lc].lazy=0; use[lc].sum=mid-l+1-use[lc].sum; } else { use[lc].lazy=3; use[lc].sum=mid-l+1-use[lc].sum; } if(use[rc].lazy==1) { use[rc].lazy=2; use[rc].sum=0; } else if(use[rc].lazy==2) { use[rc].lazy=1; use[rc].sum=r-mid; } else if(use[rc].lazy==3) { use[rc].lazy=0; use[rc].sum=r-mid-use[rc].sum; } else { use[rc].lazy=3; use[rc].sum=r-mid-use[rc].sum; } } use[rt].lazy=0; } } iv change(int rt,int l,int r,int L,int R,int z) { if(L<=l&&r<=R) { if(z==1) { use[rt].sum=r-l+1; use[rt].lazy=1; } else if(z==2) { use[rt].sum=0; use[rt].lazy=2; } else { if(use[rt].lazy==3) { use[rt].lazy=0; use[rt].sum=r-l+1-use[rt].sum; } else if(use[rt].lazy==1) { use[rt].lazy=2; use[rt].sum=0; } else if(use[rt].lazy==2) { use[rt].lazy=1; use[rt].sum=r-l+1; } else { use[rt].sum=r-l+1-use[rt].sum; use[rt].lazy=3; } } return; } pd(rt,l,r); if(mid>=L) { change(lc,l,mid,L,R,z); } if(mid<R) { change(rc,mid+1,r,L,R,z); } pp(rt); } ii query(int rt,int l,int r) { if(l==r) return lsh[l]; pd(rt,l,r); if(use[lc].sum<(mid-l+1)) return query(lc,l,mid); return query(rc,mid+1,r); } }T; ii read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=0; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return (f)?x:(-x); } signed main() { m=read(); int maxx=0; for(re i=1;i<=m;i++) { ty=read(); ul=read(); ur=read(); v[i].push_back(ty); v[i].push_back(ul); v[i].push_back(ur); maxx=max(maxx,ur); lsh[++cnt]=ul; lsh[++cnt]=ur; lsh[++cnt]=ul+1; lsh[++cnt]=ur+1; } lsh[++cnt]=1; maxx++; sort(lsh+1,lsh+cnt+1); cnt=unique(lsh+1,lsh+cnt+1)-lsh-1; maxx=lower_bound(lsh+1,lsh+cnt+1,maxx)-lsh; for(re i=1;i<=m;i++) { v[i][1]=lower_bound(lsh+1,lsh+cnt+1,v[i][1])-lsh; v[i][2]=lower_bound(lsh+1,lsh+cnt+1,v[i][2])-lsh; } int ans=0; for(re i=1;i<=m;i++) { ans=0; T.change(1,1,maxx,v[i][1],v[i][2],v[i][0]); ans=T.query(1,1,maxx); printf("%lld\n",ans); } return 0; }
T2 賽
思路:這道題我們利用一個多指標的思想,首先先將物品分成四類,AB都喜歡,A喜歡B不喜歡,A不喜歡B喜歡,AB都不喜歡,這樣我們將他們儲存起來並從大到小排序,然後先假設全部選擇AB都喜歡的物品,接著將指標進行移動,我在程式中標記了4個我的出錯點,具體實現見程式碼:
#include<bits/stdc++.h> #define int long long #define re register int #define ii inline int #define iv inline void using namespace std; const int N=2e5+10; const int INF=1e15; struct CUN { int v; friend bool operator < (CUN a,CUN b) { return a.v<b.v; } }cun[N],use1[N],use2[N],use3[N],use4[N]; bool vis1[N],vis2[N]; int n,m,k,a,b; int cnt1,cnt2,cnt3,cnt4,c1,c2,c3,c4; int ans=INF,out; ii read() { int x=0; bool f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=0; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } return f?x:(-x); } inline bool pd() { if(cnt1>=m&&m<k) return 1; if(cnt1+cnt2<k||cnt1+cnt3<k||k*2>m+cnt1)//3 return 1; return 0; } #undef int int main() { #define int long long n=read(); m=read(); k=read(); for(re i=1;i<=n;i++) cun[i].v=read(); a=read(); for(re i=1;i<=a;i++) vis1[read()]=1; b=read(); for(re i=1;i<=b;i++) vis2[read()]=1; for(re i=1;i<=n;i++) { if(vis1[i]&&vis2[i]) use1[++cnt1].v=cun[i].v; else if(vis1[i]) use2[++cnt2].v=cun[i].v; else if(vis2[i]) use3[++cnt3].v=cun[i].v; else use4[++cnt4].v=cun[i].v; } if(pd()) { printf("-1\n"); return 0; } sort(use1+1,use1+cnt1+1); sort(use2+1,use2+cnt2+1); sort(use3+1,use3+cnt3+1); sort(use4+1,use4+cnt4+1); c1=min(cnt1,m); if(c1<m)//1 { c2=c3=max(0ll,k-cnt1); int now=m-c1-c2-c3; while(now--) { if(use2[c2+1]<use3[c3+1]&&use2[c2+1]<use4[c4+1]) c2++; else if(use3[c3+1]<use2[c2+1]&&use3[c3+1]<use4[c4+1]) c3++; else c4++; } } for(re i=1;i<=c1;i++) out+=use1[i].v; for(re i=1;i<=c2;i++) out+=use2[i].v; for(re i=1;i<=c3;i++) out+=use3[i].v; for(re i=1;i<=c4;i++) out+=use4[i].v; ans=min(ans,out); while(c1) { c1--; out-=use1[c1+1].v; int fl=0; if(c1+c2<k&&c2<cnt2) { ++c2; out+=use2[c2].v; ++fl; } if(c1+c3<k&&c3<cnt3) { ++c3; out+=use3[c3].v; ++fl; } if(fl==2) { if(c4==0) break;//2 out-=use4[c4].v; --c4; } else if(!fl)//4 { if(use2[c2+1].v<use3[c3+1].v&&use2[c2+1].v<use4[c4+1].v) { ++c2; out+=use2[c2].v; } else if(use3[c3+1].v<use2[c2+1].v&&use3[c3+1].v<use4[c4+1].v) { ++c3; out+=use3[c3].v; } else { ++c4; out+=use4[c4].v; } } ans=min(ans,out); } printf("%lld\n",ans); return 0; }
T3 題
思路:
但是,我們不能暴力列舉每個狀態,但是我們可以利用逆向思維反向推出合法的狀態,具體實現見程式碼:
#include<bits/stdc++.h> #define re register int #define ii inline int #define iv inline void using namespace std; const int N=410; const int M=5e4+10; struct CUN { int u,v; }use[M]; int n,m,ans; int f[N]; bitset<N>g[N]; ii read() { int x=0; bool f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=0; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } return f?x:(-x); } int main() { n=read(); m=read(); for(re i=1;i<=m;i++) { use[i].u=read(); use[i].v=read(); } for(re i=1;i<=n;i++) { f[i]=1; g[i][i]=1; for(re j=m;j;j--) { int U=use[j].u,V=use[j].v; if(g[i][U]&&g[i][V]) { f[i]=0; break; } if((!g[i][U])&&(!g[i][V])) continue; g[i][U]=1; g[i][V]=1; } } for(re i=1;i<=n;i++) { if(!f[i]) continue; for(re j=i+1;j<=n;j++) { if(!f[j]) continue; if((g[i]&g[j])!=0) continue; ++ans; } } printf("%d\n",ans); return 0; }