多校第二场,依靠罚时优点打到了校内的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要么想线段树花了一段时间。
不过仍是很高兴的,出题人用心出题目,用脚造数据