zoukankan      html  css  js  c++  java
  • SNOI2017(BZOJ5015~5018)泛做

    T1:礼物

    想错方向了,实际上很简单。

    我想的是:显然题目求的是$sum_{i=1}^{n} i^{k}2^{i}$,然后或许可以通过化式子变成与n无关的复杂度?

    然后就不停往斯特林数反演和下降幂的方向想,最后什么都没想出来。

    其实想一会就应该意识到:这完全就是一个不可直接化简的式子啊。

    $A[i]$表示第$i$个人送的礼物数,$S[i]$为前缀和,那么显然有$S[i]=2*S[i-1]+i^k$,这样就把思路引导矩乘方面去了。

    如何矩乘呢?考虑题目的提示。首先$i^k$这个东西不好直接转移到$(i+1)^k$,其次发现转移的话根据二项式定理需要$i^1,i^2,...,i^k$的所有数,最后从题目“$K leq 10$”可以猜到,一定是将$i^1 i^2 ... i^k$全部扔进矩阵,和$S[i]$一起转移,转移矩阵则正好是$C_i^j$的转置矩阵,这样就可以$O(log n imes k^3)$解决问题

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const ll P=1000000007;
     9 ll n,c[20][20];
    10 int m;
    11 
    12 struct M{ ll a[20][20]; M(){ memset(a,0,sizeof(a)); } }tr,a1,a2;
    13 M mul(M a,M b){
    14     M c;
    15     rep(i,0,m+1) rep(j,0,m+1) rep(k,0,m+1) c.a[i][k]=(c.a[i][k]+a.a[i][j]*b.a[j][k])%P;
    16     return c;
    17 }
    18 
    19 M ksm(M a,ll b){
    20     M x=tr;
    21     for (; b; x=mul(x,x),b>>=1)
    22         if (b & 1) a=mul(a,x);
    23     return a;
    24 }
    25 
    26 int main(){
    27     scanf("%lld%d",&n,&m);
    28     rep(i,0,m) c[i][0]=1;
    29     rep(i,1,m) rep(j,1,i) c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
    30     rep(i,0,m){
    31         a1.a[0][i]=a2.a[0][i]=1;
    32         rep(j,0,i) tr.a[j][i]=c[i][j];
    33     }
    34     tr.a[m+1][m+1]=2; tr.a[m][m+1]=1;
    35     a1=ksm(a1,n-1); a2=ksm(a2,n);
    36     printf("%lld
    ",(a2.a[0][m+1]-a1.a[0][m+1]+P)%P);
    37     return 0;
    38 }
    View Code

    T2:一个简单的询问

    求和上面的无穷符号第一眼有点吓人,实际上就是n。

    看数据范围就知道是分块。怎么分?这个虽然简单,但还是有点难想的。$$get(l1,r1,x) imes get(l2,r2,x)$$$$= (get(l1,r1,x)-get(1,l1-1,x))   imes (get(l2,r2,x)-get(1,l2-1,x))$$$$= get(1,r1,x) imes get(1,r2,x)-get(1,r1,x) imes get(1,l2-1,x)-get(1,l1-1,x) imes get(1,r2,x)+get(1,l1-1,x) imes get(1,l2-1,x)$$

    这样就可以看出来是莫队了,这里的莫队已经不是传统的$[L,R]$区间询问了,而是真正的曼哈顿最小生成树的替代品。

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=50100;
     9 ll res[N],ans;
    10 int n,m,a[N],l1,r1,l2,r2,L,R,tot,num1[N],num2[N];
    11 struct Q{ int l,r,k,id,pos; }q[N<<2];
    12 bool cmp(Q a,Q b){ return (a.pos==b.pos) ? a.r<b.r : a.pos<b.pos; }
    13 
    14 int main(){
    15     scanf("%d",&n); int bl=sqrt(n);
    16     rep(i,1,n) scanf("%d",&a[i]);
    17     scanf("%d",&m);
    18     rep(i,1,m){
    19         scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
    20         q[++tot]=(Q){l1-1,l2-1,1,i,(l1-2)/bl+1}; q[++tot]=(Q){r1,r2,1,i,(r1-1)/bl+1};
    21         q[++tot]=(Q){l1-1,r2,-1,i,(l1-2)/bl+1}; q[++tot]=(Q){r1,l2-1,-1,i,(r1-1)/bl+1};
    22     }
    23     sort(q+1,q+tot+1,cmp);
    24     rep(i,1,tot){
    25         while (R<q[i].r) ans+=num1[a[++R]],num2[a[R]]++;
    26         while (L>q[i].l) ans-=num2[a[L]],num1[a[L--]]--;
    27         while (R>q[i].r) ans-=num1[a[R]],num2[a[R--]]--;
    28         while (L<q[i].l) ans+=num2[a[++L]],num1[a[L]]++;
    29         res[q[i].id]+=ans*q[i].k;
    30     }
    31     rep(i,1,m) printf("%lld
    ",res[i]);
    32     return 0;
    33 }
    View Code 

     T3:炸弹

    想不到想不到,线段树的新应用。
    首先可以看出是图论,每个炸弹向可以引爆的炸弹连边,强连通块$Tarjan$缩点后建出反图,再按拓扑序跑一遍$DP$计数即可,这是暴力。
    发现每个点连出去的所有点一定是一段连续的区间,所以可以想到线段树。所以我们先按照线段树的方法建点连边,这样最后最多只会有$O(nlog n)$个点和$O(nlog n)$条边了。
    发现有不少关于区间的问题可以往线段树方面想。
    无故$CE$了$5$发,至今未$AC$,改了$cin$和$cout$也过不了,明明没有任何编译错误信息,辣鸡$BZOJ$。

     1 #include<cstdio>
     2 #include<queue>
     3 #include<iostream>
     4 #include<algorithm>
     5 #define ls (x<<1)
     6 #define rs ((x<<1)|1)
     7 #define lson ls,L,mid
     8 #define rson rs,mid+1,R
     9 #define rep(i,l,r) for (int i=l; i<=r; i++)
    10 typedef long long ll;
    11 using namespace std;
    12 
    13 const int N=2000100,M=20000100,mod=1000000007;
    14 int scc,n,tim,top,dfn[N],low[N],ind[N],inq[N],stk[N],bel[N],pos[N];
    15 ll ans,a[N],p[N],v[N],Min[N],Max[N],mn[N],mx[N];
    16 queue<int>Q;
    17 
    18 struct Graph{
    19     int cnt,to[M],nxt[M],h[N];
    20     void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    21     void tarjan(int x){
    22         dfn[x]=low[x]=++tim; inq[x]=1; stk[++top]=x;
    23         for (int i=h[x],k; i; i=nxt[i])
    24             if (!dfn[k=to[i]]) tarjan(k),low[x]=min(low[x],low[k]);
    25                 else if (inq[k]) low[x]=min(low[x],dfn[k]);
    26         if (low[x]==dfn[x]){
    27             scc++; int t;
    28             do{
    29                 t=stk[top--]; bel[t]=scc; inq[t]=0;
    30                 Min[scc]=min(Min[scc],mn[t]);
    31                 Max[scc]=max(Max[scc],mx[t]);
    32             }while (t!=x);
    33         }
    34     }
    35 }G,G1;
    36 
    37 void build(int x,int L,int R){
    38     if (L==R) { pos[L]=x; return; }
    39     int mid=(L+R)>>1; mn[x]=1ll<<62; mx[x]=-(1ll<<62);
    40     build(lson); build(rson);
    41     G.add(x,ls); G.add(x,rs);
    42 }
    43 
    44 void upd(int x,int L,int R,int k,int l,int r){
    45     if (L==l && r==R) { G.add(k,x); return; }
    46     int mid=(L+R)>>1;
    47     if (r<=mid) upd(lson,k,l,r);
    48     else if (l>mid) upd(rson,k,l,r);
    49         else upd(lson,k,l,mid),upd(rson,k,mid+1,r);
    50 }
    51 
    52 int main(){
    53     freopen("bzoj5017.in","r",stdin);
    54     freopen("bzoj5017.out","w",stdout);
    55     ios::sync_with_stdio(false);
    56     cin>>n; build(1,1,n);
    57     rep(i,1,n) cin>>a[i]>>v[i],mn[pos[i]]=mx[pos[i]]=a[i];
    58     a[n+1]=1ll<<62;
    59     rep(i,1,n){
    60         int l=lower_bound(a+1,a+n+2,a[i]-v[i])-a;
    61         int r=upper_bound(a+1,a+n+2,a[i]+v[i])-a-1;
    62         upd(1,1,n,pos[i],l,r);
    63     }
    64     rep(i,1,n<<2) if (!dfn[i]) G.tarjan(i);
    65     rep(x,1,n<<2) for (int i=G.h[x],k; i; i=G.nxt[i])
    66         if (bel[x]!=bel[k=G.to[i]]) G1.add(bel[k],bel[x]),ind[bel[x]]++;
    67     rep(i,1,scc) if (!ind[i]) Q.push(i);
    68     while (!Q.empty()){
    69         int x=Q.front(); Q.pop();
    70         for (int i=G1.h[x],k; i; i=G1.nxt[i]){
    71             ind[k=G1.to[i]]--; Min[k]=min(Min[k],Min[x]),Max[k]=max(Max[k],Max[x]);
    72             if (!ind[k]) Q.push(k);
    73         }
    74     }
    75     rep(i,1,n){
    76         int r=upper_bound(a+1,a+n+1,Max[bel[pos[i]]])-a;
    77         int l=lower_bound(a+1,a+n+1,Min[bel[pos[i]]])-a;
    78         ans=(ans+1ll*(r-l)*i)%mod;
    79     }
    80     cout<<ans<<endl;
    81     return 0;
    82 }
    View Code

    T4:英雄联盟。
    一眼想出暴力做法,发现连暴力分都拿不到,然后就不会了。
    一看题解,发现暴力就是正解,十分崩溃。
    $f[i][j]$表示前$i$个英雄花$j$元所能得到的最多方案数,直接转移,普及组难度。
    可能会爆$long long$,所以所有大于$m$的都记成等于就好了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=l; i<=r; i++)
     4 typedef long long ll;
     5 using namespace std;
     6 
     7 ll f[125][250010],m,t;
     8 int n,c[125],k[125];
     9 
    10 int main(){
    11     scanf("%d%lld",&n,&m);
    12     rep(i,1,n) scanf("%d",&k[i]);
    13     rep(i,1,n) scanf("%d",&c[i]);
    14     f[0][0]=1;
    15     rep(i,1,n){
    16         rep(j,0,t) f[i][j]=f[i-1][j];
    17         rep(j,2,k[i]) rep(l,c[i]*j,t+c[i]*j)
    18             f[i][l]=min(m,max(f[i][l],(ll)f[i-1][l-j*c[i]]*j));
    19         t+=c[i]*k[i];
    20     } 
    21     rep(i,0,t) if(f[n][i]>=m) { printf("%d
    ",i); return 0; }
    22     return 0;
    23 }
    View Code
  • 相关阅读:
    使用jq.lazyload.js,解决设置loading图片的问题
    Write your first jQuery plugin
    如何在Less中使用使用calc
    web页面在ios下不支持fixed可用absolute替代的方案
    JavaScript内存优化
    js监听文本框内容变化
    动态绑定事件on
    CSS秘密花园:多边框
    2020—2021—1学期20202405《网络空间安全导论》第一周学习总结
    2020—2021—1学期20202405《网络空间安全导论》第五周学习总结
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8728512.html
Copyright © 2011-2022 走看看