zoukankan      html  css  js  c++  java
  • [jzoj NOIP2018模拟10.23]

    丢分主要是下面几个方面:

    1.T2代码交错了,有个特判没写丢了10分

    2.T1线段树加等差数列写错了(其实二维差分就可以,但我当时不会)

    3.T3思考再三还是为了10分写上了主席树,还是写错了

    总体评价就是和正解没什么联系,暴力也没写满


    T1:sequence

    题目链接:

    http://172.16.0.132/senior/#contest/show/2535/0

    题目:

    小 F 是一位 Hack 国的居民,他生活在一条长度为 n 的街道上,这个街道上总共有 n 个商店。每个商店里售卖着不同的 Hack 技能包,每个商店本身也会有个便利值。初始时,每个商店的便利值均为 0。每一天,街道上都会有一些商店优化改造。
    具体来说,对于每一天,优化改造的商店都是一个连续的区间 l ∼ r,每次优化改造也会有一个优化参数 k。对于所有 l ≤ i ≤ r ,第 i 个商店的便利值会增加


    小 F 想知道,m 天之后,每个商店的便利值分别是多少。由于小 F 并不喜欢高精度,因此你只需要输出便利值对 10^9 + 7 取模的结果。

    题解:

    考虑一个下标从 0 开始的数列,这个数列的每个数均为 1。 我们对这个数列做$ k$ 阶前缀和,得到的数列第i项的值为$dbinom{k+i}{k}$。

    于是我们发现题目中的这个加法实际上就是对当前的序列的第$k+1$阶差分(考虑到影响0阶前缀和的是1阶差分序列,影响$k$阶前缀和的就是$k+1$阶差分序列),设第$k$阶差分数组为$cha[k]$,那么题目中的这个加法产生的效果就是$cha[k+1][l]++,cha[k+1][r+1]--$

    但如果是这样的话还是不行的,我们还需要对$1~k$阶差分序列的第$r+1$项做一些运算,设当前为第i阶差分序列(1<=i<=k),在第r+1位减去$dbinom{r-l+k-(i-1)}{k-(i-1)}$,即减去当前差分序列的前缀和,为的是消去对后面的影响

    可以手推一下样例方便理解

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    
    const int N=5e5+15;
    const int mo=1e9+7;
    int n,m;
    ll cha[25][N],s[25][N],ans[N],C[N][25];
    inline int read(){
        char ch=getchar();int s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    } 
    int main()
    {
        freopen("sequence.in","r",stdin);
        freopen("sequence.out","w",stdout);
        C[0][0]=1;
        for (int i=1;i<N;i++)
            for (int j=0;j<25;j++)
            {
                if (!j) C[i][j]=1;
                else C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
            }
        n=read();m=read();
        while (m--)
        {
            int l=read(),r=read(),k=read();
            cha[k+1][l]++;cha[k+1][r+1]--;
            for (int i=k;i;i--)
            {
                cha[i][r+1]=(cha[i][r+1]+mo-C[k-(i-1)+r-l][k-(i-1)])%mo;
            }
        }
        for (int i=20;i>=0;i--) 
        {
            for (int j=1;j<=n;j++) s[i][j]=(cha[i+1][j]+s[i][j-1]+mo)%mo;
            for (int j=1;j<=n;j++) cha[i][j]=(cha[i][j]+mo+s[i][j]+mo)%mo;
        }
        for (int i=1;i<=n;i++) printf("%lld
    ",cha[0][i]);
        return 0;
    }
    View Code

    T2:Bomb 

    题目链接:

    http://172.16.0.132/senior/#contest/show/2535/1

    题目:

      常数国与 Hack 国近年来战火纷飞。
      常数国共有 n 个城市,每两个城市之间均有一条交通线联通。如今常数国遭到 Hack 国的重创,岌岌可危。Hack 国国王小 K 决定轰炸常数国的交通线,对常数国发起最后的攻击。
      面对危难之时,常数国国王决定更换首都。在 Hack 国的轰炸结束之后,常数国的领土将会分成若干个联通块。常数国的首都,将会从联通块大小最大的联通块中,随机选择一个城市,作为首都。
      小 K 得知了常数国的应对方案之后,他想知道,Hack 国有多少种不同的轰炸方案,使得常数首都所在的联通块大小恰好为 k。两种轰炸方案是不同的,当且仅当一条交通线在一种方案中存在,在另一种方案中被轰炸。由于方案数可能很大,你需要输出方案数对 998,244,353 取模的结果。

    题意:

    询问n个有编号点形成的最大连通块为k的方案数

    首先我们要知道这么一个式子,设$f_n$为$n$个有编号节点的连通图的方案数,$f_i=2^{dbinom{i}{2}}-sum_{j=1}^{n-1}2^{dbinom{i-j}{2}}dbinom{i-1}{j-1} f_j$

    现在回到题目,设$p_i$表示i个有标号节点的最大连通块等于k的连通图的个数,$p_n$即为答案;设$q_i$表示i个有标号节点的最大连通块小于等于k的连通图的个数

    考虑初始化:$p_0=0,q_0=1$

    考虑转移:$sum_{j=1}^{min(i,k)}$

    egin{equation}
    left{
    egin{array}{lr}
    p_i+=p_{i-j} imes dbinom{i-1}{j-1} f_j, j<k&\
    p_i+=q_{i-j} imes dbinom{i-1}{j-1}f_j, j=k&
    \q_i+=q_{i-j} imes dbinom{i-1}{j-1}f_j&
    end{array}
    ight.
    end{equation}

    #include<algorithm>
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    
    const int N=2e3+15;
    const int mo=998244353;
    int n,k;
    ll C[N][N],f[N],p[N],q[N];
    ll qpow(ll a,ll b)
    {
        ll re=1;
        for (;b;b>>=1,a=a*a%mo) if (b&1) re=re*a%mo;
        return re;
    }
    int main()
    {
        freopen("bomb.in","r",stdin);
        freopen("bomb.out","w",stdout);
        scanf("%d%d",&n,&k);
        C[0][0]=1;
        for (int i=1;i<=n;i++)
            for (int j=0;j<=i;j++)
            {
                if (!j) C[i][j]=1;
                else C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
            }
        f[0]=1;f[1]=1;
        for (int i=2;i<=n;i++)
        {
            ll re=qpow(2,C[i][2]);
            for (int j=1;j<i;j++) re=(re+mo-qpow(2,C[i-j][2])*C[i-1][j-1]%mo*f[j]%mo)%mo;
            f[i]=re;
        }
        q[0]=1;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=min(i,k);j++)
            {
                if (j<k)
                {
                    p[i]=(p[i]+p[i-j]*C[i-1][j-1]%mo*f[j]%mo)%mo;
                }
                if (j==k)
                {
                    p[i]=(p[i]+q[i-j]*C[i-1][j-1]%mo*f[j]%mo)%mo;
                }
                q[i]=(q[i]+q[i-j]*C[i-1][j-1]%mo*f[j]%mo)%mo;
            }
        printf("%lld
    ",p[n]);
        return 0;
    }
    View Code

    T3:queue

    题目链接:

    http://172.16.0.132/senior/#contest/show/2535/2

    题目:

    题解:

    考虑分块,块内元素我们用链表相连,维护每个快内每个元素出现的个数。显然对于询问我们可以整块询问,边界暴力

    考虑轮转操作,我们把r所在元素从r所在连通块删去,然后加入到l之前的位置。设l所在连通块为k1,r所在连通块为k2,让k1到k2-1每个连通块都把最后一个元素丢给后面一个连通块,这样我们就保证了连通块的大小不变了

    时间复杂度显然是带根号的

    deque实现链表方便的多

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    #include<deque>
    #include<cmath>
    using namespace std;
    
    const int N=1e5+15;
    int n,m;
    int qu[500][N],belong[N],st[N],ed[N],a[N];
    deque <int> bl[N];
    inline int read(){
        char ch=getchar();int s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    int main(){
        freopen("queue.in","r",stdin);
        freopen("queue.out","w",stdout);
        n=read();m=read();
        if (!n&&!m) return 0;
        for (int i=1;i<=n;i++) a[i]=read();
        int blo=sqrt(n);
        for (int i=1;i<=n;i++) belong[i]=(i-1)/blo+1;
        for (int i=1;i<=n;i++) bl[belong[i]].push_back(a[i]),qu[belong[i]][a[i]]++;
        for (int i=1;i<=(n-1)/blo+1;i++) 
        {
            st[i]=(i-1)*blo+1;ed[i]=min(i*blo,n);
        }
        while (m--)
        {
            int opt=read();
            if (opt==1)
            {
                int l=read(),r=read(),k1=belong[l],k2=belong[r];
                int k=bl[k2][r-st[k2]];
                bl[k2].erase(bl[k2].begin()+r-st[k2]);
                qu[k2][k]--;
                bl[k1].insert(bl[k1].begin()+l-st[k1],k);
                qu[k1][k]++;
                if (k1==k2) continue;
                for (int i=k1;i<k2;i++)
                {
                    k=bl[i].back();
                    bl[i].erase(bl[i].end()-1);
                    qu[i][k]--;
                    bl[i+1].push_front(k);
                    qu[i+1][k]++;
                }
            }
            if (opt==2)
            {
                int l=read(),r=read(),k=read(),k1=belong[l],k2=belong[r];
                int re=0;
                if (k1==k2)
                {
                    for (int i=l-st[k1];i<=r-st[k1];i++) if (bl[k1][i]==k) ++re;
                    continue;
                }
                for (int i=l-st[k1];i<=ed[k1]-st[k1];i++) 
                {
                    if (bl[k1][i]==k) ++re;
                }
                for (int i=0;i<=r-st[k2];i++) if (bl[k2][i]==k) ++re;
                if (k1+1<=k2-1)
                {
                    for (int i=k1+1;i<k2;i++) re+=qu[i][k];
                }
                printf("%d
    ",re);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    极高效内存池实现 (cpu-cache)
    gles2.0环境的在windows上的建立
    使用OpenGL绘制 shapefile文件 完成最基本的gis操作
    纯C++安卓开发 (ndk)系列之 ---- 常见问题
    如何用 纯C++(ndk)开发安卓应用 ?
    Android-NDK处理用户交互事件
    图解-安卓中调用OpenGL
    图解安卓-c++开发-通过java 调用c++ jni的使用
    搭建安卓开发环境 hello world andriod
    关于socket通讯,如何才能高效?
  • 原文地址:https://www.cnblogs.com/xxzh/p/9841497.html
Copyright © 2011-2022 走看看