zoukankan      html  css  js  c++  java
  • 10.03模拟总结

    国庆模拟真愉快,真愉快!这只是个开始,之后我们还有4天连续的国庆模拟呢!而且可能不会像今天这么好改了orz。

    来吧,我们来看看这些题。

    T1.matrix

    这道题考试的时候只想到了60分的暴力维护……就是只开一维差分,另一维直接暴力去修改……,不过这样的复杂度是O(np)的,这个肯定会超时。

    然后大致想到了使用二维差分去维护,不过不知道怎么实现。(知道查询是可以用前缀和查询的,但是修改怎么修啊orz)

    考试结束后听bin哥一讲就明白了,我们只要在右上和左下+1,左下和右上-1即可,这样的话我们就能保证原数组就是差分数组的前缀和。(只要简单想想就能知道啦)

    之后我们再跑一遍,维护一次前缀和。

    查询的适合只要用四个矩形互相加减即可,老套路了。

    来看一下满分的代码。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define de putchar('#')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int N = 2005;
    const int INF = 1000000009;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    
    int n,m,p,q,dx,dy,sx,sy,c[N][N];
    ll a[N][N];
    
    void build()
    {
        rep(q,1,2)
        {
            rep(i,1,n-1)
            rep(j,1,m) a[i+1][j] += a[i][j];
            rep(i,1,n)
            rep(j,1,m-1) a[i][j+1] += a[i][j];
        }
    }
    
    int main()
    {
        freopen("matrix.in","r",stdin);
        freopen("matrix.out","w",stdout);
        n = read(),m = read(),p = read(),q = read();
        rep(i,1,p)
        {
            dx = read(),dy = read(),sx = read(),sy = read();
            a[dx][dy]++,a[dx][sy+1]--,a[sx+1][dy]--,a[sx+1][sy+1]++;
        }
        build();
        rep(i,1,q)
        {
            dx = read(),dy = read(),sx = read(),sy = read();
            ll g = a[sx][sy] + a[dx-1][dy-1] - a[sx][dy-1] - a[dx-1][sy];
            printf("%lld
    ",g);
        }
        return 0;
    }

    T2.card

    好吧说实话第一眼我以为这是个组合题,还以为这是个与HNOI2008那道组合很相像的一道题。不过那道题要求维护的是相同的,那个其实特别好计算,而这道题是要求维护的是相邻两个数只和不能等于k,这个就很麻烦。

    我一开始想能不能用组合的方法解决……好吧显然不行。这玩意咋组合啊……反正我是想不出来。想了一段时间之后我觉得换个思路,用递推的方式来做。我只考虑了k  < m的情况,设f[i]表示第i个数选择了1~k-1范围之内的数的方案数,g[i]表示第i个数选择了k~m范围内的数的方案树。

    于是乎我们有如下转移:

    f[i] = f[i-1] * (k-2) + g[i-1] * (k-1) (还有取模)

    g[i] = (g[i-1] + f[i-1]) * (m-k+1) (取模)

    然后我就这么傻不拉几的交了上去,还得了50pts。

    其实我考试结束之前10分钟突然发现这玩意可以用矩阵加速……然后我没时间写了。

    哦,对于k > m的情况,一开始我听了ssy神犇的讲述……不过后来觉得好像还是自己想好懂一些。

    其实完全可以照着k < m去推的,这次令f[i]表示选取1~k-m-1的情况的方案数,g[i]表示选择k-m~m的情况的方案数。于是得到以下方程:

    f[i] = (f[i-1]  + g[i-1])* (k-m-1);

    g[i] = f[i-1] * (2m-k+1) + g[i-1] * (2m-k)

    然后这玩意也可以用矩阵加速!然后就可以A了!

    看一下满分代码。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define de putchar('#')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    using namespace std;
    typedef long long ll;
    const int M = 2000005;
    const ll mod = 1000000007;
    
    ll read()
    {
        ll ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    ll m,n,k,f[M],g[M],ans;
    
    
    struct matrix
    {
        ll h[3][3];
        matrix()
        {
            memset(h,0,sizeof(h));
        }
        friend matrix operator * (const matrix &a,const matrix &b)
        {
            matrix c;
            rep(i,1,2)
            rep(j,1,2)
            rep(k,1,2) c.h[i][j] += (a.h[i][k] * b.h[k][j]) % mod,c.h[i][j] %= mod;
            return c;
        }
    }a;
    
    matrix mpow(matrix a,ll b)
    {
        matrix p;
        rep(i,1,2) p.h[i][i] = 1;
        while(b)
        {
        if(b & 1) p = p * a;
        a = a * a;
        b >>= 1;
        }
        return p;
    }
    
    int main()
    {
        //freopen("card.in","r",stdin);
        //freopen("card.out","w",stdout);
        m = read(),n = read(),k = read();
        if(k > m)
        {
        a.h[1][1] = (k-m-1) % mod,a.h[1][2] = (k-m-1) % mod;
        a.h[2][1] = (2*m-k+1) % mod,a.h[2][2] = (2*m-k) % mod;
        matrix d = mpow(a,n-1);
        f[1] = (k-m-1) % mod,g[1] = (2*m-k+1) % mod;
        f[2] = (f[1] * d.h[1][1]) % mod + (g[1] * d.h[1][2]) % mod,f[2] %= mod;
        g[2] = (f[1] * d.h[2][1]) % mod + (g[1] * d.h[2][2]) % mod,g[2] %= mod;
        printf("%lld
    ",(f[2] + g[2]) % mod);
        return 0;
        }
        a.h[1][1] = (k-2) % mod,a.h[1][2] = (k-1) % mod;
        a.h[2][1] = (m-k+1) % mod,a.h[2][2] = (m-k+1) % mod;
        matrix d = mpow(a,n-1);
        f[1] = (k-1) % mod,g[1] = (m-k+1) % mod;
        f[2] = (f[1] * d.h[1][1]) % mod + (g[1] * d.h[1][2]) % mod,f[2] %= mod;
        g[2] = (f[1] * d.h[2][1]) % mod + (g[1] * d.h[2][2]) % mod,g[2] %= mod;
        printf("%lld
    ",(f[2] + g[2]) % mod);
        return 0;
    }

    T3.station

    这题考试的时候我还是只能想到O(nq)模拟,就是维护一下前缀和然后硬算。

    然后莫名其妙的爆零了orz……

    后来发现,其实对于每个村庄的距离,他相对于上一个村庄的距离就是加上左边的前缀和,减去右边的前缀和,所以其实它是有一定的单调性的。所以其实它是可以使用树状数组维护的……这倒是学了一招,可以直接维护现在的人数总和,然后其实我们只要在树状数组上二分一个人数总和的一半即可,那个位置一定是最小值。

    我们来看一下代码吧。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define de putchar('#')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    #define lowbit(x) x & (-x)
    using namespace std;
    typedef long long ll;
    const int M = 300005;
    const ll INF = 1000000000009;
    const ll mod = 998244353;
    
    ll read()
    {
        ll ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    
    ll naive[M],n,q,a[M],p,b,ans,s,minn,mpos,w = 1;
    
    void add(ll x,ll y)
    {
        while(x < M) a[x] += y,x += lowbit(x);
        s += y;
    }
    
    int query(ll x)
    {
        int t = 0;
        ll cur = 0;
        for(int i = (1 << 17);i;i >>= 1) if(cur + a[t+i] <= x) cur += a[t += i];
        return t + 1;
    }
    
    int main()
    {
            freopen("station.in","r",stdin);
        freopen("station.out","w",stdout);
        n = read(),p = read();
        rep(i,1,n) b = read(),add(i,b);
        while(p--)
        {
            q = read(),b = read(),add(q,b);
            w *= 19260817ll,w %= mod;
            ans += w * query((s-1) >> 1),ans %= mod;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    想做的事情
    js学习笔记2(5章操作方法)
    js学习笔记1(变量、作用域、内存)
    输入框去除默认的文字,jquery方法
    同类型元素,只有一个被选中js
    淘宝分类常见---部分显示和全部显示的js效果
    关于游戏提名信息项目的总结
    20174310隋润起网络对抗免考报告
    2019-2020-2 20174310 隋润起《网络对抗技术》Exp9 Web安全基础
    2019-2020-2 20174310隋润起《网络对抗技术》Exp8 Web基础
  • 原文地址:https://www.cnblogs.com/captain1/p/9741418.html
Copyright © 2011-2022 走看看