多校第二場,依靠罰時優點打到了校內的Rank 2ios
暴力分塊碾標算系列數組
題目大意:在一個數集\([1,n]\)中兩我的輪流選擇其中的一個數,並從數集中刪去這個數全部約數。先將全部數刪去的人獲勝。post
比賽的時候手玩了\(n<=5\)的狀況發現TM的怎麼老是先手贏啊,而後就認爲這是個先手必勝的遊戲然而真的是這樣spa
賽後聽法老講了真正的作法,分假定狀況討論:翻譯
故先手必勝,CODEcode
#include<cstdio> using namespace std; int n; int main() { while (scanf("%d",&n)!=EOF) puts("Yes"); return 0; }
題目大意:給出一個數列,你能夠花費\(x\)的代價交換兩個數。在交換結束以後,還要花費\(y*逆序對個數\)的代價。問最小的代價。遊戲
這個一個結論:交換次數等於逆序對個數,所以樹狀數組求逆序對以後乘上\(\min(x,y)\)便可。ip
CODEci
#include<cstdio> #include<cctype> #include<algorithm> #include<cstring> using namespace std; const int N=100005; int a[N],bit[N],b[N],n,m,x,y; long long ans; inline int find(int x) { int l=1,r=m,mid; while (l<=r) { mid=l+r>>1; if (b[mid]==x) return mid; if (b[mid]<x) l=mid+1; else r=mid-1; } } inline int lowbit(int x) { return x&-x; } inline int get(int x) { int res=0; for (;x<=m;x+=lowbit(x)) res+=bit[x]; return res; } inline void add(int x) { for (;x;x-=lowbit(x)) ++bit[x]; } int main() { register int i; while (scanf("%d%d%d",&n,&x,&y)!=EOF) { for (i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i]; memset(bit,0,sizeof(bit)); sort(b+1,b+n+1); m=unique(b+1,b+n+1)-b-1; for (ans=0,i=1;i<=n;++i) { a[i]=find(a[i]); ans+=get(a[i]+1); add(a[i]); } printf("%lld\n",ans*(x<y?x:y)); } return 0; }
題目大意:這題不用翻譯也能看懂吧,畢竟都是常見套路。給你兩個數組\(a,b\),初始時\(a\)的全部元素都爲\(0\)。而後定義兩種操做:get
官方給出的解法是搞兩棵線段樹,而後一波操做反正我不會
比賽的時候YY了一個延時修改的分塊,2000+ms卡過。
首先咱們記錄一個塊內的答案,而後考慮何時這個值纔會被修改。
固然是有個數\(i\)(或多個)的值被累加到多出一個\(b_i\)來了。
有了這個思想,咱們再維護一下每一塊內最少還要整塊累加多少次就會使答案發生改變,記做\(v_i\)。
而後修改的時候兩端仍是暴力改,整塊的話也弄一個標記。
而後核心的來了,咱們修改的時候不更新整塊標記,而是查詢的時候改
查詢仍是先暴力計算兩端,而後對於被查詢的塊,看一下整塊的累加是否已經超過\(v_i\),是的話再更新。
通常狀況下速度良好,大體\(O(n\sqrt n\cdot k)\),\(k\)爲常數,大體在\([In^2\ n,In\ n]\)吧,其實主要仍是和\(b_i\)的關係比較大。
塊樂的CODE
#include<iostream> #include<cstdio> #include<string> #include<cmath> #include<cstring> using namespace std; typedef long long LL; const int N=100005,BLO=320; int n,m,a[N],b[N],l,r,blk[N],v[BLO],t[BLO],size; LL sum[BLO]; string s; inline int min(int a,int b) { return a<b?a:b; } inline void reset(int id) { register int i; v[id]=1e9; for (i=(id-1)*size+1;i<=id*size;++i) { sum[id]-=a[i]/b[i]; a[i]+=t[id]; sum[id]+=a[i]/b[i]; v[id]=min(v[id],b[i]-a[i]%b[i]); } t[id]=0; } inline void modify(int l,int r) { register int i; for (i=l;i<=min(blk[l]*size,r);++i) { if (!(++a[i]%b[i])) ++sum[blk[l]]; v[blk[l]]=min(v[blk[l]],b[i]-a[i]%b[i]); } if (blk[l]!=blk[r]) for (i=(blk[r]-1)*size+1;i<=r;++i) { if (!(++a[i]%b[i])) ++sum[blk[r]]; v[blk[r]]=min(v[blk[r]],b[i]-a[i]%b[i]); } for (i=blk[l]+1;i<=blk[r]-1;++i) ++t[i]; } inline LL query(int l,int r) { register int i; LL tot=0; for (i=l;i<=min(blk[l]*size,r);++i) tot+=(a[i]+t[blk[l]])/b[i]; if (blk[l]!=blk[r]) for (i=(blk[r]-1)*size+1;i<=r;++i) tot+=(a[i]+t[blk[r]])/b[i]; for (i=blk[l]+1;i<=blk[r]-1;++i) { if (t[i]>=v[i]) reset(i); tot+=sum[i]; } return tot; } int main() { //freopen("7.in","r",stdin); freopen("7.out","w",stdout); ios::sync_with_stdio(false); register int i; while (cin>>n>>m) { memset(a,0,sizeof(a)); memset(v,63,sizeof(v)); memset(t,0,sizeof(t)); memset(sum,0,sizeof(sum)); for (size=sqrt(n),i=1;i<=n;++i) cin>>b[i],blk[i]=(i-1)/size+1,v[blk[i]]=min(v[blk[i]],b[i]); while (m--) { cin>>s; cin>>l>>r; if (s[0]=='a') modify(l,r); else cout<<query(l,r)<<endl; } } return 0; }
主要是其餘隊伍要麼沒寫出T7要麼想線段樹花了一段時間。
不過仍是很高興的,出題人用心出題目,用腳造數據