【ContestHunter】【弱省胡策】【Round7】

Prufer序列+高精度+组合数学/DP+可持久化线段树


Magic

  利用Prufer序列,我们考虑序列中每个点是第几个插进去的,再考虑环的连接方式,我们有$$ans=\sum_{K=3}^n N^{N-K-1}*K*\frac{(K-1)!}{2} * \binom{N}{K}$$

  然而直接高精算会爆……

  注意到每一项与前一项相差不大,有$now=last*N/(N-K+1)$,所以我们算出来第一项以后不用每次重算后面的了……

 1 //Round7 A
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define rep(i,n) for(int i=0;i<n;++i)
 8 #define F(i,j,n) for(int i=j;i<=n;++i)
 9 #define D(i,j,n) for(int i=j;i>=n;--i)
10 #define pb push_back
11 using namespace std;
12 typedef long long LL;
13 const int N=100010;
14 /*******************template********************/
15 
16 int n;
17 struct bint{
18     LL v[1500];
19     int l;
20     LL& operator [] (int x){return v[x];}
21     bint(){l=0; memset(v,0,sizeof v);}
22 }ans;
23 const LL Limit=100000000000000LL;
24 void print(bint& a){
25     printf("%lld",a[a.l]);
26     D(i,a.l-1,1) printf("%014lld",a[i]);
27     puts("");
28 }
29 void mul(bint& a,const int &b){
30     LL tmp=0;
31     F(i,1,a.l){
32         a[i]=a[i]*b+tmp;
33         tmp=a[i]/Limit;
34         a[i]%=Limit;
35     }
36     if (tmp) a[++a.l]=tmp;
37 }
38 void del(bint& a,const int &b){
39     LL tmp=0,last=0;
40     D(i,a.l,1){
41         tmp=(a[i]+last*Limit)%b;
42         a[i]=(a[i]+last*Limit)/b;
43         last=tmp;
44     }
45     while(a[a.l]==0 && a.l) a.l--;
46 }
47 bint operator + (bint a,bint b){
48     int l=max(a.l,b.l);
49     F(i,1,l){
50         a[i]+=b[i];
51         if (a[i]>=Limit) a[i]-=Limit,a[i+1]++;
52     }
53     if (a[l+1]>0) a.l=l+1; else a.l=l;
54     return a;
55 }
56 int main(){
57 #ifndef ONLINE_JUDGE
58     freopen("A.in","r",stdin);
59     freopen("A.out","w",stdout);
60 #endif
61     scanf("%d",&n);
62     bint p,ans;
63     p[p.l=1]=1;
64     F(i,1,n-2) mul(p,n);
65     mul(p,n-1);
66     del(p,2);
67     F(k,3,n){
68         mul(p,n-k+1);
69         del(p,n);
70         ans=ans+p;
71 //        ans+=Pow(n,n-k-1)*k*fac[k-1]/2*C(n,k);
72     }
73     print(ans);
74     return 0;
75 }
View Code

Rectangle

  QwQ真是一道好题!

  先考虑所有的a[i]=1的情况,这时候我们的做法是线段树维护最大连续区间。

  然后我们推广一下,用可持久化线段树,对每一个高度都维护一个最大连续区间。

  同时再用一个priority_queue来维护一下当前的答案!(官方题解这里说是set……然而我用set给MLE了!什么鬼!!)

  

  1 //Round7 B
  2 #include<cstdio>
  3 #include<queue>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<iostream>
  7 #include<algorithm>
  8 #define rep(i,n) for(int i=0;i<n;++i)
  9 #define F(i,j,n) for(int i=j;i<=n;++i)
 10 #define D(i,j,n) for(int i=j;i>=n;--i)
 11 #define pb push_back
 12 using namespace std;
 13 typedef long long LL;
 14 inline LL getint(){
 15     LL r=1,v=0; char ch=getchar();
 16     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
 17     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
 18     return r*v;
 19 }
 20 const int N=100001,M=1000001;
 21 /*******************template********************/
 22 
 23 int n,m,Max,a[N],b[N],rt[M],cnt;
 24 
 25 struct node{
 26     int l,r,maxl,maxr,max;
 27 }t[10000001];
 28 #define L t[o].l
 29 #define R t[o].r
 30 #define mid (l+r>>1)
 31 #define lch L,l,mid
 32 #define rch R,mid+1,r
 33 void build(int &o,int l,int r){
 34     o=++cnt;
 35     t[o].maxl=t[o].maxr=t[o].max=r-l+1;
 36     if (l==r) return;
 37     build(lch);
 38     build(rch);
 39 }
 40 inline void maintain(int o,int l,int r){
 41     t[o].maxl=t[L].maxl; t[o].maxr=t[R].maxr;
 42     if (t[L].maxl==mid-l+1) t[o].maxl+=t[R].maxl;
 43     if (t[R].maxr==r-mid) t[o].maxr+=t[L].maxr;
 44     t[o].max=max(t[L].maxr+t[R].maxl,max(t[L].max,t[R].max));
 45 }
 46 void update(int &o,int l,int r,int pos){
 47     t[++cnt]=t[o], o=cnt;
 48     if (l==r){t[o].maxl=t[o].maxr=t[o].max=0;return;}
 49     if (pos<=mid) update(lch,pos);
 50     else update(rch,pos);
 51     maintain(o,l,r);
 52 }
 53 bool cmp(int x,int y){return a[x]<a[y];}
 54 struct data{
 55     LL v;
 56     int id;
 57     data(LL x=0,int id=0):v(x),id(id){}
 58     bool operator < (const data &b)const{
 59         return v<b.v || (v==b.v && id>b.id);
 60     }
 61 };
 62 priority_queue<data>Q;
 63 int main(){
 64 #ifndef ONLINE_JUDGE
 65     freopen("B.in","r",stdin);
 66     freopen("B.out","w",stdout);
 67 #endif
 68     n=getint(); m=getint();
 69     Max=0;
 70     F(i,1,n){
 71         a[i]=getint();
 72         Max=max(Max,a[i]);
 73         b[i]=i;
 74     }
 75     sort(b+1,b+n+1,cmp);
 76     build(rt[0],1,n);
 77 
 78     LL ans=0;
 79     for(int i=1,j=1;i<=Max;i++){
 80         rt[i]=rt[i-1];
 81         for(;a[b[j]]==i-1 && j<=n;j++)
 82             update(rt[i],1,n,b[j]);
 83         Q.push(data((LL)t[rt[i]].max*i,i));
 84 //        printf("height=%d val=%lld\n",i,(LL)t[rt[i]].max*i);
 85     }
 86 
 87     data x=Q.top();
 88     printf("%lld\n",ans=x.v);
 89     LL pos;
 90     while(m--){
 91         pos=getint()^ans;
 92         update(rt[a[pos]],1,n,pos);
 93         Q.push(data((LL)t[rt[a[pos]]].max*a[pos],a[pos]));
 94         a[pos]--;
 95         for(x=Q.top(); (LL)x.id*t[rt[x.id]].max!=x.v;Q.pop(),x=Q.top());
 96         ans=Q.top().v;
 97         printf("%lld\n",ans);
 98     }
 99     return 0;
100 }
View Code

 

转载于:https://www.cnblogs.com/Tunix/p/4587162.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值