zoukankan      html  css  js  c++  java
  • 2019NC#8

    题号标题已通过代码题解/讨论通过率团队的状态
    A All-one Matrices 点击查看 单调栈+前缀和 326/2017  通过
    B Beauty Values 点击查看 进入讨论 827/1995  通过
    C CDMA 点击查看 进入讨论 669/1115  通过
    D Distance 点击查看 理性暴力 37/554 OK
    E Explorer 点击查看 可修改并查集,LCT 83/920 OK
    F Flower Dance 点击查看 进入讨论 13/121 未通过
    G Gemstones 点击查看 进入讨论 883/2062  通过
    H How Many Schemes 点击查看 进入讨论 3/61 未通过
    I Inner World 点击查看 dfs序,矩形面积 17/94 OK
    J Just Jump 点击查看 DP,容斥 85/532 OK
     

     A - All-one Matrices

    题意:

    给定一个n × m的 01矩阵,输出极大全1子矩阵的个数。

    思路:

    先搞出每个点向下能走的距离。

    利用单调栈维护每个点最左能到达的值,由于有相同的情况,所以要跑两次单调栈,

    第一次求出每个点最左能到的地方。

    第二次要弹栈的,判断是否能作为子矩阵的最上层,计入答案。

    // #pragma GCC optimize(2)
    // #pragma GCC optimize(3)
    // #pragma GCC optimize(4)
    #include <algorithm>
    #include  <iterator>
    #include  <iostream>
    #include   <cstring>
    #include   <cstdlib>
    #include   <iomanip>
    #include    <bitset>
    #include    <cctype>
    #include    <cstdio>
    #include    <string>
    #include    <vector>
    #include     <stack>
    #include     <cmath>
    #include     <queue>
    #include      <list>
    #include       <map>
    #include       <set>
    #include   <cassert>
    // #include<bits/extc++.h>
    // using namespace __gnu_pbds;
    using namespace std;
    #define pb push_back
    #define fi first
    #define se second
    #define debug(x) cerr<<#x << " := " << x << endl;
    #define bug cerr<<"-----------------------"<<endl;
    #define FOR(a, b, c) for(int a = b; a <= c; ++ a)
    
    typedef long long ll;
    typedef long double ld;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    
    const int inf = 0x3f3f3f3f;
    const ll inff = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9+7;
    
    template<typename T>
    inline T read(T&x){
        x=0;int f=0;char ch=getchar();
        while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x=f?-x:x;
    }
    
    /**********showtime************/
    
                const int maxn = 3009;
                char str[maxn][maxn];
                int sum[maxn][maxn];
                int dp[maxn][maxn];
                int ls[maxn];
                stack<pii>st;
    int main(){
                int n,m;
                scanf("%d%d", &n, &m);
                for(int i=1; i<=n; i++) scanf("%s", str[i] + 1);
                for(int i=1; i<=n; i++) {
                    for(int j=1; j<=m; j++) {
                        sum[i][j] = sum[i][j-1];
                        if(str[i][j] == '1') sum[i][j] ++;
                    }
                }
    
                for(int i=n; i>=1; i--) {
                    for(int j=1; j<=m; j++) {
                        if(str[i][j] == '1') dp[i][j] = dp[i+1][j] + 1;
                        else dp[i][j] = 0;
                    }
                }
    
                int ans = 0;
                for(int i=1; i<=n; i++) {
    //                debug(i);
                    while(!st.empty()) st.pop();
                    st.push(pii(-1, 0));
                    for(int j=1; j<=m; j++) {
                            while(!st.empty() && st.top().fi >= dp[i][j]) {
                                st.pop();
                            }
                            ls[j] = st.top().se + 1;
                            st.push(pii(dp[i][j], j));
                    }
                    while(!st.empty()) st.pop();
                     for(int j=1; j<=m + 1; j++) {
                        while(!st.empty() && st.top().fi > dp[i][j]) {
                            int le = ls[st.top().se], ri = j - 1;
                            st.pop();
                            if(sum[i-1][ri] - sum[i-1][le-1] == ri - le + 1) continue;
                            ans++;
                        }
                        if(j < m + 1 && (st.empty() || dp[i][j] > st.top().fi) )st.push(pii(dp[i][j], j));
                    }
    
                }
                printf("%d
    ", ans);
                return 0;
    }
    /*
    5 5
    11111
    11110
    11100
    11100
    10000
    3 6
    001000
    011011
    010011
    
    */
    View Code

    D-Distance

    思路

    考虑非情况,如果点数不多,就枚举点数,如果点数很多,就把这么多点的影响通过bfs记录下来。

    /*
    * @Author: chenkexing
    * @Date:   2019-08-11 21:48:52
    * @Last Modified by:   chenkexing
    * @Last Modified time: 2019-08-11 23:23:57
    */
    
    // #pragma GCC optimize(2)
    // #pragma GCC optimize(3)
    // #pragma GCC optimize(4)
    #include <algorithm>
    #include  <iterator>
    #include  <iostream>
    #include   <cstring>
    #include   <cstdlib>
    #include   <iomanip>
    #include    <bitset>
    #include    <cctype>
    #include    <cstdio>
    #include    <string>
    #include    <vector>
    #include     <stack>
    #include     <cmath>
    #include     <queue>
    #include      <list>
    #include       <map>
    #include       <set>
    #include   <cassert>
    // #include<bits/extc++.h>
    // using namespace __gnu_pbds;
    using namespace std;
    #define pb push_back
    #define fi first
    #define se second
    #define debug(x) cerr<<#x << " := " << x << endl;
    #define bug cerr<<"-----------------------"<<endl;
    #define FOR(a, b, c) for(int a = b; a <= c; ++ a)
    
    typedef long long ll;
    typedef long double ld;
    typedef pair<int, int> pii;
    typedef pair<int, pii> p3;
    typedef pair<ll, ll> pll;
    
    const int inf = 0x3f3f3f3f;
    const ll inff = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9+7;
    
    template<typename T>
    inline T read(T&x){
        x=0;int f=0;char ch=getchar();
        while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x=f?-x:x;
    }
    
    /**********showtime************/
    
                const int maxn = 1e5+9;
                int n,m,h,q;
                int getid(int x, int y, int z) {
                    return (z - 1)* (n * m) + (x-1)*m + y;
                }
                vector<int>vx,vy,vz;
                int dis[maxn];
                int xia[8][3] = {{0,0,1},{0,1,0},{1,0,0}, {-1, 0 ,0 }, {0, -1 ,0 }, {0, 0 ,-1 }};
                void rebuild(){
                    queue< p3>que;
                    for(int i=0; i<vx.size(); i++) {
                            int nx = vx[i];
                            int ny = vy[i];
                            int nz = vz[i];
                            dis[getid(nx, ny, nz)] = 0;
                            que.push(p3(nx, pii(ny, nz)));
                    }
                    vx.clear();
                    vy.clear();
                    vz.clear();
                    while(!que.empty()) {
                        p3 tmp = que.front(); que.pop();
                        int x = tmp.fi;
                        int y = tmp.se.fi;
                        int z = tmp.se.se;
                        for(int i=0; i<6; i++) {
                            int nx = x + xia[i][0];
                            int ny = y + xia[i][1];
                            int nz = z + xia[i][2];
                            if(nx <= 0 || nx > n || ny <= 0|| ny > m || nz <= 0 || nz > h) continue;
                            if(dis[getid(nx, ny, nz)] > dis[getid(x, y, z)] + 1) {
                                dis[getid(nx, ny, nz)] = dis[getid(x, y, z)] + 1;
                                que.push(p3(nx, pii(ny, nz)));
                            }
                        }
                    }
    
                }
    int main(){
                scanf("%d%d%d%d", &n, &m, &h, &q);  
                int E = sqrt(n * m * h) + 1;
                memset(dis, inf, sizeof(dis));
    
                while(q--) {
                    int op, x, y, z;
                    scanf("%d%d%d%d", &op, &x, &y, &z);
                    if(op == 1) {
                        vx.pb(x);
                        vy.pb(y);
                        vz.pb(z);
                    }
                    else {
                        int ans = dis[getid(x, y, z)];
                        for(int i=0; i<vx.size(); i++) {
                            int nx = vx[i];
                            int ny = vy[i];
                            int nz = vz[i];
                            ans = min(ans, abs(nx - x) + abs(ny - y) + abs(nz - z));
                        }
                        printf("%d
    ", ans);
                    }
                    if(vx.size() >= E) rebuild();
                }
                return 0;
    }
    View Code

     

    E - Explorer

    可撤回的并查集

    利用线段树优化

    注意每次从左子树或者右子树回来的时候,都要进行清空。

    // #pragma GCC optimize(2)
    // #pragma GCC optimize(3)
    // #pragma GCC optimize(4)
    #include <algorithm>
    #include  <iterator>
    #include  <iostream>
    #include   <cstring>
    #include   <cstdlib>
    #include   <iomanip>
    #include    <bitset>
    #include    <cctype>
    #include    <cstdio>
    #include    <string>
    #include    <vector>
    #include     <stack>
    #include     <cmath>
    #include     <queue>
    #include      <list>
    #include       <map>
    #include       <set>
    #include   <cassert>
    // #include<bits/extc++.h>
    // using namespace __gnu_pbds;
    using namespace std;
    #define pb push_back
    #define fi first
    #define se second
    #define debug(x) cerr<<#x << " := " << x << endl;
    #define bug cerr<<"-----------------------"<<endl;
    #define FOR(a, b, c) for(int a = b; a <= c; ++ a)
    
    typedef long long ll;
    typedef long double ld;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    
    const int inf = 0x3f3f3f3f;
    const ll inff = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9+7;
    
    template<typename T>
    inline T read(T&x){
        x=0;int f=0;char ch=getchar();
        while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x=f?-x:x;
    }
    const int N = 1e5+9;
    
    /// 可撤回并查集模板
    struct UFS {
        stack<pair<int*, int>> stk;
        int fa[N], rnk[N];
        inline void init(int n) {
            for (int i = 0; i <= n; ++i) fa[i] = i, rnk[i] = 0;
        }
        inline int Find(int x) {
            while(x^fa[x]) x = fa[x];
            return x;
        }
        inline void Merge(int x, int y) {
            x = Find(x), y = Find(y);
            if(x == y) return ;
            if(rnk[x] <= rnk[y]) {
                stk.push({fa+x, fa[x]});
                fa[x] = y;
                if(rnk[x] == rnk[y]) {
                    stk.push({rnk+y, rnk[y]});
                    rnk[y]++;
                }
            }
            else {
                stk.push({fa+y, fa[y]});
                fa[y] = x;
            }
        }
        inline void Undo() {
            *stk.top().fi = stk.top().se;
            stk.pop();
        }
    }T;
    /**********showtime************/
                const int maxn = 1e5+9;
                int n,m;
                struct E{
                    int u, v, le, ri;
                    void init(int U, int V, int Le, int Ri) {
                        u = U; v = V;
                        le = Le; ri = Ri;
                    }
                } edge[maxn];
    
                vector<int>vec;
                int getid(int x) {
                    return lower_bound(vec.begin(), vec.end(), x) - vec.begin() + 1;
                }
    
                vector <int> node[maxn * 8];
                int sz[maxn * 8];
                void update(int L, int R, int id, int le, int ri, int rt) {
                    if(le >= L && ri <= R) {
                        node[rt].pb(id);
                        return;
                    }
                    int mid = (le + ri) >> 1;
                    if(mid >= L) update(L, R, id, le, mid, rt<<1);
                    if(mid < R) update(L, R, id, mid+1, ri, rt<<1|1);
                }
                ll ans = 0;
                
                void dfs(int le, int ri, int rt) {
                    for(int id : node[rt]) {
                        T.Merge(edge[id].u, edge[id].v);
                    }
                    int sz = T.stk.size();
                    if(le == ri) {
                        if(T.Find(1) == T.Find(n)) {
    //                        cout<<ri<<endl;
                            ans += vec[ri] - vec[le-1];
                        }
    
                        return;
                    }
                    int mid = (le + ri) >> 1;
                    dfs(le, mid, rt<<1);
                    while(T.stk.size() > sz) {
                        T.Undo();
                    }
                    dfs(mid+1, ri, rt<<1|1);
                    while(T.stk.size() > sz) {
                        T.Undo();
                    }
                }
    int main(){
                scanf("%d%d", &n, &m);
                T.init(n);
                for(int i=1; i<=m; i++) {
                    int u,v,le,ri;
                    scanf("%d%d%d%d", &u, &v, &le, &ri);
                    edge[i].init(u, v, le, ri+1);
                    vec.pb(le);
                    vec.pb(ri + 1);
                }
                sort(vec.begin(), vec.end());
                vec.erase(unique(vec.begin(), vec.end()), vec.end());
                int tot = vec.size();
                for(int i=1; i<=m; i++) {
                    int l = getid(edge[i].le);
                    int r = getid(edge[i].ri) - 1;
    //                cout<<l<<" " << r << endl;
                    update(l, r, i, 1, tot-1, 1);
                }
                ans = 0;
                dfs(1, tot-1, 1);
                printf("%lld
    ", ans);
                return 0;
    }
    View Code

    I - Inner World

    先把n个子树看成一颗树,相同的点合并到一起,附加一个区间信息就行了。

    然后利用dfs序+前缀和的思想处理询问即可

    // #pragma GCC optimize(2)
    // #pragma GCC optimize(3)
    // #pragma GCC optimize(4)
    #include <algorithm>
    #include  <iterator>
    #include  <iostream>
    #include   <cstring>
    #include   <cstdlib>
    #include   <iomanip>
    #include    <bitset>
    #include    <cctype>
    #include    <cstdio>
    #include    <string>
    #include    <vector>
    #include     <stack>
    #include     <cmath>
    #include     <queue>
    #include      <list>
    #include       <map>
    #include       <set>
    #include   <cassert>
    // #include<bits/extc++.h>
    // using namespace __gnu_pbds;
    using namespace std;
    #define pb push_back
    #define fi first
    #define se second
    #define debug(x) cerr<<#x << " := " << x << endl;
    #define bug cerr<<"-----------------------"<<endl;
    #define FOR(a, b, c) for(int a = b; a <= c; ++ a)
    
    typedef long long ll;
    typedef long double ld;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    
    const int inf = 0x3f3f3f3f;
    const ll inff = 0x3f3f3f3f3f3f3f3f;
    const int mod = 998244353;
    
    template<typename T>
    inline T read(T&x){
        x=0;int f=0;char ch=getchar();
        while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x=f?-x:x;
    }
    /**********showtime************/
    
                const int maxn = 3e5+9;
    
                int le[maxn],ri[maxn];
                vector<int>mp[maxn];
                int id[maxn], dfn[maxn], tim = 0, sz[maxn];
                void dfs(int u) {
                    dfn[u] = ++tim;
                    id[tim] = u;
                    sz[u] = 1;
                    for(int v : mp[u]) {
                        dfs(v);
                        sz[u] += sz[v];
                    }
                }
                struct node{
                    int le, ri, id, op;
                    node(int Le, int Ri, int Id, int Op){
                        le = Le; ri = Ri; id = Id; op = Op;
                    }
                };
                vector<node> g[maxn];
                ll ans[maxn];
                struct TT{
                    ll sum[maxn<<2], lazy[maxn<<2];
                    void pushdown(int le, int ri, int rt) {
                        lazy[rt<<1] += lazy[rt];
                        lazy[rt<<1|1] += lazy[rt];
                        int mid = (le + ri) >> 1;
                        sum[rt<<1] += 1ll*lazy[rt] * (mid - le + 1);
                        sum[rt<<1|1] += 1ll*lazy[rt] * (ri - mid);
                        lazy[rt] = 0;
                    }
                    void update(int L, int R, int c, int le, int ri, int rt) {
                        if(le >= L && ri <= R) {
                            sum[rt] += 1ll * c * (ri - le + 1);
                            lazy[rt] += 1ll * c;
                            return ;
                        }
                        int mid = (le + ri) >> 1;
                        if(lazy[rt]) pushdown(le , ri, rt);
                        if(L <= mid) update(L, R, c, le, mid, rt<<1);
                        if(mid < R) update(L, R, c, mid+1, ri, rt<<1|1);
                        sum[rt] = sum[rt<<1] + sum[rt<<1|1];
                    }
                    ll query(int L, int R, int le, int ri, int rt) {
                        if(le >= L && ri <= R) {
                            return sum[rt];
                        }
                        int mid = (le + ri) >> 1;
                        if(lazy[rt]) pushdown(le, ri, rt);
                        ll res = 0;
                        if(L <= mid) res += query(L, R, le, mid, rt<<1);
                        if(mid < R) res += query(L, R, mid+1, ri,rt<<1|1);
                        return res;
                    }
                } tree;
    int main(){
                int n,m;
                scanf("%d%d", &n, &m);
                le[1] = 1, ri[1] = n;
                for(int i=1; i<=m; i++) {
                    int u,v,l,r;
                    scanf("%d%d%d%d", &u, &v, &l, &r);
                    mp[u].pb(v);
                    le[v] = l, ri[v] = r;
                }
                int N = m + 1;
                ///dfs序,将一个点的子树表示成一个区间
                dfs(1);
    
                int q;  scanf("%d", &q);
                for(int i=1; i<=q; i++) {
                    int u, le, ri;
                    scanf("%d%d%d", &u, &le, &ri);
                    int t1 = dfn[u] - 1;
                    ///将一次询问拆成两次操作,类似于把区间和改为前缀和相减
                    g[t1].pb(node(le, ri, i, -1));
                    g[t1 + sz[u]].pb(node{le, ri, i, 1});
                }
    
                for(int i=1; i<=tim; i++) {
                    int u = id[i];
                    tree.update(le[u], ri[u], 1, 1, n, 1);
                    ///因为是二维面积,所以要用线段树等数据结构维护前缀和
                    for(node a : g[i]) {
                        ans[a.id] += 1ll * a.op * tree.query(a.le, a.ri, 1, n, 1);
                    }
                }
    
                for(int i=1; i<=q; i++) printf("%lld
    ", ans[i]);
                return 0;
    }
    /*
    4 3
    1 2 1 2
    1 3 2 4
    3 4 2 3
    2
    1 1 4
    3 1 4
    */
    View Code

    J - Just Jump

    由于有m个限制,我们就计算出m个对应点不合法方案的个数。

    这里要利用容斥,第i个点不合法的方案要减去之前就不合法的点转移过来的方案。

    然后dp转移。

     O($m ^ 2 + n$)的复杂度

     从一个点x转移到y,走p步,每步长度要大于t,的方案数。可以转化为小球放入盒子中的问题。

    设x到y之间有n个点,

    就可以转化为有n个小球,分到p个盒子中,每个盒子至少要有t个小球。

    那么我们先安排每个盒子t个小球。

    那么剩下的$ n - t imes p$个小球放入盒子中,盒子可以为空。

    这个怎么做呢,我们利用隔板法,多放入$ n - t imes p$个盒子,选出 p - 1个盒子作为隔板即可。

    $dbinom{n - p imes t + p - 1}{p-1}$

    // #pragma GCC optimize(2)
    // #pragma GCC optimize(3)
    // #pragma GCC optimize(4)
    #include <algorithm>
    #include  <iterator>
    #include  <iostream>
    #include   <cstring>
    #include   <cstdlib>
    #include   <iomanip>
    #include    <bitset>
    #include    <cctype>
    #include    <cstdio>
    #include    <string>
    #include    <vector>
    #include     <stack>
    #include     <cmath>
    #include     <queue>
    #include      <list>
    #include       <map>
    #include       <set>
    #include   <cassert>
    // #include<bits/extc++.h>
    // using namespace __gnu_pbds;
    using namespace std;
    #define pb push_back
    #define fi first
    #define se second
    #define debug(x) cerr<<#x << " := " << x << endl;
    #define bug cerr<<"-----------------------"<<endl;
    #define FOR(a, b, c) for(int a = b; a <= c; ++ a)
    
    typedef long long ll;
    typedef long double ld;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    
    const int inf = 0x3f3f3f3f;
    const ll inff = 0x3f3f3f3f3f3f3f3f;
    const int mod = 998244353;
    
    template<typename T>
    inline T read(T&x){
        x=0;int f=0;char ch=getchar();
        while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x=f?-x:x;
    }
    /**********showtime************/
                const int maxn=1e7+10;
                ll A[maxn];
                ll B[maxn];
                ll quick(int x,int n){
                    ll ans=1;
                    while(n){
                        if(n&1) ans=1ll*ans*x%mod;
                        x=1ll*x*x%mod;
                        n=n/2;
                    }
                    return ans;
                }
                void init(){
                    int n=maxn-1;
                    A[0]=1; B[0]=1;
                    for(int i=1;i<=n;i++) A[i]=1ll*A[i-1]*i%mod;
                    B[n]=quick(A[n],mod-2);
                    for(int i=n-1;i>=1;i--) B[i]=1ll*B[i+1]*(i+1)%mod;
                }
                ll CC(ll n,ll x){
                    if(x>n) return 0;
                    return 1ll*A[n]*B[n-x]%mod*B[x]%mod;
                }
                ll dp[maxn];
                ll s[3009], sum[maxn];
                pii a[3009];
    int main(){
                init();
    //            debug(CC(500, 1));
                int L,d,m;
                scanf("%d%d%d", &L, &d, &m);
                for(int i=1; i<=m; i++) {
                    scanf("%d%d", &a[i].se, &a[i].fi);
                }
                sort(a + 1, a + 1 + m);
                for(int i=1; i<=m; i++) {
                    ll pos = a[i].fi, t = a[i].se;
                    s[i] = CC(pos - t * d + t - 1, t - 1);
    //                cout<<s[i]<<" ";
                    for(int j=1; j<i; j++){
                        if(a[j].fi < a[i].fi && a[j].se < a[i].se) {
                            ll prepos = a[j].fi, pret = a[j].se;
                            ll n = pos - prepos, tt = t - pret;
                            s[i] = (s[i] - 1ll*s[j] * CC(n - tt * d + tt - 1, tt - 1)%mod + mod) % mod;
                        }
                    }
    
                    dp[pos] =((dp[pos] - s[i])% mod + mod) % mod;
                }
    //            cout<<endl;
                dp[0] = 1;
                sum[0] = 1;
                for(int i=1; i<=L; i++) {
                    if(i-d >= 0) dp[i] += sum[i-d];
                    dp[i] = dp[i] % mod;
                    sum[i] = (sum[i-1] + dp[i]) % mod;
    //                cout<<dp[i]<<" ";
                }
    //            cout<<endl;
                printf("%lld
    ", dp[L]);
                return 0;
    }
    /*
    5 2 4
    1 2
    2 5
    2 8
    2 9
    */
    View Code
  • 相关阅读:
    BZOJ1001 BJOI2006 狼抓兔子
    NOI2015 程序自动分析
    高斯消元法
    [POJ] 3666 Making the Grade
    [CODEVS] 2185 最长公共上升子序列
    [模板] LIS
    [CF] 219D Choosing Capital for Treeland
    [POJ] 2823 Sliding Window
    [BZOJ] 1072 [SCOI2007]排列perm
    [POJ] 1094 Sorting It All Out
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/11332868.html
Copyright © 2011-2022 走看看