zoukankan      html  css  js  c++  java
  • 补题

    1. 1303F

    大意: 给定$n imes m$矩阵, 初始全$0$, 若相邻两格元素相同, 那么它们连通. 每次操作修改元素的值, 求矩阵中连通块的个数. 


    因为颜色比较少, 可以分别考虑每种颜色, 那么修改操作就等价于删点和添点. 添点用并查集很容易维护, 删点倒序处理即可.  

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    const int dx[]={0,0,-1,1};
    const int dy[]={-1,1,0,0};
    const int N = 2e6+10;
    int n,m,q,a[350][350];
    struct _ {
        int x,y,id;
    };
    vector<_> del[N],add[N];
    int fa[N],ans[N];
    int Find(int x) {return fa[x]?fa[x]=Find(fa[x]):x;}
    int ID(int x, int y) {return (x-1)*m+y;}
    
    void solve(vector<_> &v, int c) {
        REP(i,1,n) REP(j,1,m) a[i][j] = 0;
        REP(i,0,n*m) fa[i] = 0;
            for (auto t:v) {
            a[t.x][t.y] = 1;
            int w = 1;
            REP(i,0,3) {
                int x=t.x+dx[i],y=t.y+dy[i];
                if (1<=x&&x<=n&&1<=y&&y<=m&&a[x][y]) {
                    int u=Find(ID(t.x,t.y)),v=Find(ID(x,y));
                    if (u!=v) --w,fa[u]=v;
                }
            }
            ans[t.id] += w*c;
        }
    }
    
    
    
    int main() {
        scanf("%d%d%d",&n,&m,&q);
        int mx = 1;
        REP(i,1,q) {
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            if (a[x][y]==c) continue;
            mx = c;
            add[c].pb({x,y,i});
            del[a[x][y]].pb({x,y,i});
            a[x][y] = c;
        }
        REP(i,1,n) REP(j,1,m) del[a[i][j]].pb({i,j,0});
        REP(i,0,mx) reverse(del[i].begin(),del[i].end());
        REP(i,0,mx) if (add[i].size()) solve(add[i],1);
        REP(i,0,mx) if (del[i].size()) solve(del[i],-1);
        int now = 1;
        REP(i,1,q) {
            now += ans[i];
            printf("%d
    ",now);
        }
    }
    View Code

    2. 1301E

    大意: 给定$n imes m$的格子, 每次操作求一个矩形内最大的合法商标面积. 


    二分答案+二维RMQ即可.

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
     
     
     
    const int N = 555;
    int n,m,q;
    char s[N][N];
    int R[N][N],G[N][N],Y[N][N],B[N][N];
    int Log[N],f[11][11][N][N];
     
    void init() {
        Log[0] = -1;
        REP(i,1,N-1) Log[i]=Log[i>>1]+1;
        REP(k,1,10) for (int i=1;i+(1<<k-1)<=n;++i) { 
            REP(j,1,m) { 
                f[k][0][i][j] = max(f[k-1][0][i][j],f[k-1][0][i+(1<<k-1)][j]);
            }
        }
        REP(l,1,10) REP(k,0,10) {
            for (int i=1;i+(k?(1<<k-1):0)<=n;++i) {
                for (int j=1;j+(1<<l-1)<=m;++j) {
                    f[k][l][i][j] = max(f[k][l-1][i][j],f[k][l-1][i][j+(1<<l-1)]);
                }
            }
        }
    }
    int RMQ(int x1, int y1, int x2, int y2) {
        if (x2<x1||y2<y1||x1<=0||y1<=0||x2>n||y2>m) return 0;
        int u = Log[x2-x1+1], v = Log[y2-y1+1];
        x2 += -(1<<u)+1, y2 += -(1<<v)+1;
        auto A = f[u][v];
        return max({A[x1][y1],A[x1][y2],A[x2][y1],A[x2][y2]});
    }
     
     
    int main() {
        scanf("%d%d%d",&n,&m,&q);
        REP(i,1,n) scanf("%s",s[i]+1);
        REP(i,1,n) REP(j,1,m) if (s[i][j]=='R') { 
            R[i][j] = min({R[i-1][j],R[i][j-1],R[i-1][j-1]})+1;
        }
        REP(i,1,n) PER(j,1,m) if (s[i][j]=='G') {
            G[i][j] = min({G[i-1][j],G[i][j+1],G[i-1][j+1]})+1;
        }
        PER(i,1,n) REP(j,1,m) if (s[i][j]=='Y') {
            Y[i][j] = min({Y[i+1][j],Y[i][j-1],Y[i+1][j-1]})+1;
        }
        PER(i,1,n) PER(j,1,m) if (s[i][j]=='B') {
            B[i][j] = min({B[i+1][j],B[i][j+1],B[i+1][j+1]})+1;
        }
        REP(i,1,n) REP(j,1,m) if (s[i][j]=='R') {
            f[0][0][i][j] = min({R[i][j],G[i][j+1],Y[i+1][j],B[i+1][j+1]});
        }
        init();
        while (q--) {
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            int l=1,r=m/2,ans=0;
            while (l<=r) {
                if (RMQ(x1+mid-1,y1+mid-1,x2-mid,y2-mid)>=mid) ans=mid,l=mid+1;
                else r=mid-1;
            }
            printf("%d
    ",4*ans*ans);
        }
    }
    View Code

    3. 1301F

    大意: 给定$n imes m$的棋盘, 每一步可以走相邻的格子,或相同颜色的格子. $q$次询问,求两点之间最短路. 


    假设只走相邻格, 那么答案就是两点间的曼哈顿距离. 否则至少走一次同色格, 并且每种同色格之间最多走一次.

    对每种颜色建一个虚点, 向对应颜色的格子连一条$0$边, 显然最短路中每个虚点最多经过$1$次.

    预处理出每个虚点到每个格子的最短路, 那么最终答案就是虚点到起点最短路+虚点到终点最短路+1

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
     
     
    const int dx[]={0,0,1,-1};
    const int dy[]={1,-1,0,0};
    const int N = 1e3+10, K = 50;
    int n,m,k,a[N][N],d[K][N][N],vis[K];
    vector<pii> g[K];
    queue<pii> q;
     
    void bfs(int x) {
        memset(d[x],0x3f,sizeof d[x]);
        memset(vis,0,sizeof vis);
        for (auto &t:g[x]) {
            d[x][t.x][t.y] = 0;
            q.push(t);
        }
        while (q.size()) {
            pii u = q.front(); q.pop();
            int c = a[u.x][u.y], w = d[x][u.x][u.y]+1;
            if (!vis[c]) {
                vis[c] = 1;
                for (auto &v:g[c]) {
                    if (d[x][v.x][v.y]>w) {
                        d[x][v.x][v.y]=w;
                        q.push(v);
                    }
                }
            }
            REP(i,0,3) {
                pii v(u.x+dx[i],u.y+dy[i]);
                if (1<=v.x&&v.x<=n&&1<=v.y&&v.y<=m) {
                    if (d[x][v.x][v.y]>w) {
                        d[x][v.x][v.y]=w;
                        q.push(v);
                    }
                }
            }
        }
    }
     
    int main() {
        scanf("%d%d%d",&n,&m,&k);
        REP(i,1,n) REP(j,1,m) {
            scanf("%d",a[i]+j);
            g[a[i][j]].pb(pii(i,j));
        }
        REP(i,1,k) bfs(i);
        int q;
        scanf("%d",&q);
        while (q--) {
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            int ans = abs(x2-x1)+abs(y2-y1);
            REP(i,1,k) ans = min(ans, d[i][x1][y1]+d[i][x2][y2]+1);
            printf("%d
    ",ans);
        }
    }
    View Code

    4. 1244F

    大意: 给定一个环, 对于每个时刻, 考虑点$i$和它左右两侧的点, 若黑色个数多, 则点$i$变为黑色, 否则变为白色. 求$k$时间后每个点颜色. 


    首先可以观察到假设相邻两点同色, 那么这两点颜色永远不会改变. 所以就把这个环拆成若干个段, 每段之间是独立的, 分别模拟一下即可.

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    const int N = 1e6+10;
    int n,k,vis[N],v[N];
    char s[N],p[N];
    
    void work(int l, int r, int k) {
        char A = s[(l-1+n)%n], B = s[(r+1)%n];
        while (v[l]&&k) {
            s[l] = A, s[r] = B;
            v[l] = v[r] = 0;
            --k,(++l)%=n,r=(r-1+n)%n;
        }
        while (v[l]) v[l]=1,s[l]="BW"[s[(l-1+n)%n]=='B'],(++l)%=n;
    }
    
    int main() {
        scanf("%d%d%s",&n,&k,s);
        int pos = -1;
        REP(i,0,n-1) if (s[i]==s[(i-1+n)%n]) pos = i;
        if (pos<0) {
            if (k&1) REP(i,0,n-1) s[i]="BW"[s[i]=='B'];
            puts(s);
            return 0;
        }
        REP(i,0,n-1) {
            //标记每段的开头: BBWB
            if (s[(i-1+n)%n]==s[(i-2+n)%n]&&s[(i-1+n)%n]!=s[i]&&s[i]!=s[(i+1)%n]) vis[i] = 1;
            //标记每段的结尾: WBB
            if (s[(i+1)%n]==s[(i+2)%n]&&s[(i+1)%n]!=s[i]) vis[i] += 2;
        }
        REP(i,0,n-1) if (vis[i]&1) {
            int j = i;
            while (vis[j]<=1) v[j]=1,(++j)%=n;
            v[j]=1;
            work(i,j,k);
        }
        puts(s);
    }
    View Code

    5. 1288D

    大意: 给定$n$个数组, 要求选出$i,j$, 构造数组$b_k=max(a_{i,k},a_{j,k})$, 满足$b_k$最小值最大. 


    状压求出状态为$s$的最小值的最大值$f[s]$, 那么答案就是$max(f[s],f[mxoplus s])$

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    const int N = 1e6+10;
    int n,m,a[N];
    pii f[N];
    void dfs(int d, int s, int x, int id) {
        if (d==m) return f[s]=max(f[s],pii(x,id)),void();
        dfs(d+1,s,x,id),dfs(d+1,s^1<<d,min(x,a[d]),id);
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        int mx = (1<<m)-1;
        REP(i,1,n) {
            REP(j,0,m-1) scanf("%d",a+j);
            dfs(0,0,2e9,i);
        }
        int ans = -1, id = 0;    
        REP(i,0,mx) {
            int w = min(f[i].x,f[mx^i].x);
            if (w>ans) ans = w, id = i;
        }
        printf("%d %d
    ",f[id].y,f[mx^id].y);
    }
    View Code

    6. 1285F

    大意: 给定序列$a$, 求$maxlimits_{1le i<jle n}LCM(a_i,a_j)$ 


    考虑枚举gcd, 问题就转化为求两个互质的数的乘积的最大值.

    考虑从大到小遍历, 维护一个栈. 假设当前遍历到$x$, 每次从栈中取出最小元素$y$.

    假设$x$和$y$互质的话, 那么$y$就可以从栈中取出, 这是因为以后遍历到的数会更小, 一定不会更优.直到栈中没有与$x$互质的为止.

    求一个序列中是否有与$x$互质的数, 就相当于求

    $sumlimits_{i=1}^{mx}{cnt}_i[gcd(i,x)=1]=sumlimits_{d|x}mu(d)sumlimits_{i=1}^{mx} [d|x]{cnt}_i$

    动态维护$f(d) = sumlimits_{i=1}^{mx} [d|x]{cnt}_i$即可.

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    const int N = 1e5+10;
    int n,a[N],mu[N],f[N];
    vector<int> c[N],s;
    
    int main() {
        REP(i,1,N-1) for (int j=i; j<N; j+=i) c[j].pb(i);
        mu[1] = 1;
        REP(i,1,N-1) for (int j=2*i; j<N; j+=i) mu[j]-=mu[i];
        scanf("%d", &n);
        ll ans = 0;
        REP(i,1,n) {
            int t;
            scanf("%d", &t);
            a[t] = 1;
            ans = max(ans, (ll)t);
        }
        REP(g,1,N-1) { 
            PER(x,1,(N-1)/g) if (a[g*x]) {
                int tot = 0;
                for (int t:c[x]) tot += mu[t]*f[t];
                while (tot) {
                    int y = s.back();
                    if (gcd(x,y)==1) {
                        ans = max(ans, (ll)g*x*y);
                        --tot;
                    }
                    for (int t:c[y]) --f[t];
                    s.pop_back();
                }
                for (int t:c[x]) ++f[t];
                s.push_back(x);
            }
            while (s.size()) { 
                for (int t:c[s.back()]) --f[t];
                s.pop_back();
            }
        }
        printf("%lld
    ", ans);
    }
    View Code

    7.  1313D

    大意: 给定$n$个区间, 保证每个点最多被$k$个区间覆盖, 可以任意删除掉区间, 求最多多少个点被奇数个区间覆盖. 


    考虑离散化, 把连续一段相同状态的点合并一下, 然后状压$DP$即可.

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    #include <set>
    #include <map>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define x first
    #define y second
    #define pb push_back
    using namespace std;
    typedef pair<int,int> pii;
     
    int n,m,k;
    vector<pii> events;
    set<int> s;
    int dp[2][260];
     
    int main() {
        scanf("%d%d%d",&n,&m,&k);
        REP(i,1,n) {
            int l,r;
            scanf("%d%d",&l,&r);
            events.pb(pii(l,i));
            events.pb(pii(r+1,-i));
        }
        sort(events.begin(),events.end());
        s.insert(events[0].y);
        map<int,int> ID[2];
        int cur = 0;
        auto upd = [&]() {
            cur ^= 1;
            memset(dp[cur],0xef,sizeof dp[0]);
            ID[cur].clear();
            int p = 0, mx = (1<<s.size())-1;
            for (auto &t:s) ID[cur][t] = p++;
        };
        auto get = [&](int x) {
            int sta = 0, p = 0;
            for (auto &t:ID[cur]) if (x>>(p++)&1) {
                if (ID[cur^1].count(t.x)) sta ^= 1<<ID[cur^1][t.x];
            }
            return sta;
        };
        for (int i=1; i<events.size(); ++i) {
            int len = events[i].x-events[i-1].x;
            if (len&&s.size()) {
                upd();
                int mx = (1<<s.size())-1;
                if (ID[cur^1].empty()) {
                    int ma = *max_element(dp[cur^1],dp[cur^1]+256);
                    REP(j,0,mx) dp[cur][j] = ma+__builtin_parity(j)*len;
                }
                else {
                    REP(j,0,mx) dp[cur][j] = max(dp[cur][j], dp[cur^1][get(j)]+__builtin_parity(j)*len);
                }
            }
            int id = events[i].y;
            if (id<0) {
                id = -id, s.erase(id), upd();
                int mx = (1<<s.size())-1;
                REP(j,0,mx) {
                    int sta = get(j);
                    dp[cur][j] = max(dp[cur^1][sta],dp[cur^1][sta^(1<<ID[cur^1][id])]);
                }
            }
            else s.insert(id);
        }
        int ans = 0;
        REP(i,0,255) ans = max(ans, dp[cur][i]);
        printf("%d
    ", ans);
    }
    View Code

    8. 1325F

    大意: 给定$n$节点无向连通图, 求找到一个$lceil sqrt{n} ceil$个点的独立集, 或长度不少于$lceil sqrt{n} ceil$的简单环. 


    考虑$dfs$树, 对深度按$mod lceil sqrt{n} ceil-1$分类, 那么如果找不到环的话, 每个分类的点之间一定不含边, 可以构成独立集, 并且最大的分类点数一定是不少于$lceil sqrt{n} ceil$

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    const int N = 1e6+50;
    int n,m,k,dep[N],fa[N],vis[N];
    vector<int> g[N],h[N];
    
    void get(int x, int y) {
        vector<int> v;
        do v.pb(x),x=fa[x]; while (x!=y);
        v.pb(y);
        printf("2
    %d
    ",(int)v.size());
        for (int t:v) printf("%d ",t);
        hr,exit(0);
    }
    
    void dfs(int x, int f, int d) {
        vis[x]=1,dep[x]=d,fa[x]=f;
        h[d%(k-1)].pb(x);
        for (int y:g[x]) if (y!=f) {
            if (!vis[y]) dfs(y,x,d+1);
            else if (d-dep[y]>=k-1) get(x,y);
        }
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        k = ceil(sqrt(n));
        REP(i,1,m) {
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].pb(v),g[v].pb(u);
        }
        dfs(1,0,0);
        REP(i,0,k-2) if (h[i].size()>=k) {
            puts("1");
            REP(j,0,k-1) printf("%d ", h[i][j]);
            return hr,0;
        }
    }
    View Code

    9. 1325E

    大意: 给定序列, 每个元素最多$7$个因子, 求一个最短的积为完全平方数的子序列.


    显然每个数最多只有两个素因子, 考虑对每个素数建一个点, 如果一个元素有两个素因子, 那么就再它们之间连一条边, 否则再建一个虚点, 把这个素数向虚点连边. 那么显然这个图的最小环就是答案.

    可以注意到对于$> sqrt{max A_i}$的点之间是不含边的, 所以一个环一定至少包含一个$<sqrt{maxA_i}$的点, 所以可以枚举这个点, 用$bfs$求最小环, 复杂度就为$O(168n)$

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    const int N = 1e6+50;
    int n,a[N],cnt,v[N],primes[N],d1[N],d2[N],f1[N],f2[N];
    vector<int> g[N],d[N];
    struct _ {int x,d,f;};
    queue<_> q;
    
    int main() {
        REP(i,2,1000) if (!v[i]) {
            primes[++cnt] = i;
            for (int j=i*i; j<=1000; j+=i) v[j]=1;
        }
        scanf("%d", &n);
        REP(i,1,n) scanf("%d",a+i);
        REP(i,1,n) {
            REP(j,1,cnt) if (a[i]%primes[j]==0) {
                int x = 0;
                while (a[i]%primes[j]==0) ++x,a[i]/=primes[j];
                if (x&1) d[i].pb(j);
            }
            if (a[i]>1) d[i].pb(a[i]);
            if (d[i].empty()) return puts("1"),0;
            if (d[i].size()==1) g[0].pb(d[i][0]),g[d[i][0]].pb(0);
            else g[d[i][0]].pb(d[i][1]),g[d[i][1]].pb(d[i][0]);
        }
        int ans = INF;
        REP(i,0,cnt) {
            sort(g[i].begin(),g[i].end());
            if (unique(g[i].begin(),g[i].end())!=g[i].end()) return puts("2");
            d1[0] = d2[0] = INF, f1[0] = f2[0] = -1;
            REP(j,1,n) for (int t:d[j]) d1[t]=d2[t]=INF,f1[t]=f2[t]=-1;
            for (int t:g[i]) q.push({t,1,t});
            while (q.size()) {
                auto [u,d,f] = q.front(); q.pop();
                if (d1[u]==INF) d1[u]=d,f1[u]=f;
                else if (d2[u]==INF&&f1[u]!=f) d2[u]=d,f2[u]=f;
                else continue;
                for (int v:g[u]) if (v!=i) q.push({v,d+1,f});
            }
            for (int v:g[i]) ans = min(ans, d2[v]+1);
        }
        if (ans>n) ans = -1;
        printf("%d
    ", ans);
    }
    View Code

    10. 1326E

    大意: 给定排列$p,q$, $p_i$表示每个元素的值, $q_i$表示位置$q_i$有炸弹. 维护一个集合$A$, 从左到右依次把$p_i$添加到$A$中, 如果$i$位置有炸弹就将$A$中最大元素弹出. 对于$1le ile n$, 输出只考虑$q_1,q_2,...,q_{i-1}$位置有炸弹时最后$A$中的最大元素. 


    跟756C非常像. 假设答案为$x$, 那么只用考虑$p$中$ge x$的元素, 每次添加一个$ge x$的元素就等价于一次$push$操作, 每碰到一个炸弹就等价于一次$pop$操作, 假设最终栈中仍有元素, 那么就说明答案是$ge x$的. 所以问题就转化为给定一个$push$和$pop$的操作序列, 求判断最终栈是否非空. 把$push$看做$1$, $pop$看做$-1$, 栈非空就等价于存在一个后缀和$>0$, 用线段树维护一个最大后缀和即可.

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
     
     
     
    const int N = 1e6+10; 
    int n,a[N],b[N],pos[N];
    struct _ {
        int ma,sum;
    } tr[N<<2];
    void pu(int o) {
        tr[o].sum=tr[lc].sum+tr[rc].sum;
        tr[o].ma=max(tr[rc].ma,tr[rc].sum+tr[lc].ma);
    }
    void add(int o, int l, int r, int x, int v) {
        if (l==r) { 
            tr[o].sum += v;
            tr[o].ma = max(0,tr[o].sum);
            return;
        }
        mid>=x?add(ls,x,v):add(rs,x,v);
        pu(o);
    }
     
    int main() {
        scanf("%d",&n);
        REP(i,1,n) scanf("%d",a+i),pos[a[i]]=i;
        REP(i,1,n) scanf("%d",b+i);
        add(1,1,n,pos[n],1);
        int ans = n;
        printf("%d ",ans);
        REP(i,1,n-1) {
            add(1,1,n,b[i],-1);
            while (!tr[1].ma) add(1,1,n,pos[--ans],1);
            printf("%d ", ans);
        }
        puts("");
    }
    View Code

    11. 1326F1

    大意: $n$个人, 给定$n imes n$矩阵表示每个人的认识关系. 一个排列$p$对应一个长$n-1$的二进制数, 假设$p_i$与$p_{i+1}$认识, 那么第$i$位为$1$, 否则为$0$. 对于所有长$n-1$的二进制数, 输出它对应多少种排列. 


    设$f_{i,j,k}$表示只考虑集合$i$, 排列长度为$j$, 排列中最后一个数为$k$, 得到的二进制数为$x$的方案数.

    考虑状态转移, 每次枚举一个不在$i$中的数$t$添加到排列末尾.

    如果$t$和$k$不认识, 那么$f_{ioplus 2^{x},j+1,t,x} leftarrow f_{i,j,k,x}$

    如果$t$和$k$认识, 那么$f_{ioplus 2^{x},j+1,t,xoplus 2^{j}} leftarrow f_{i,j,k,x}$

    这样的话复杂度是$O(n^3 4^n)$.

    实际上可以注意到$j$就是$i$中$1$的个数, 这样就可以优化掉一个$n$, 并且有效的状态$x$的个数是$2^j$, 如果只遍历有效状态的话, 复杂度就可以达到$O(n^2 3^n)$

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    int n;
    vector<ll> f[1<<14][14];
    char s[14][14];
    ll ans[1<<14];
    
    int main() {
        scanf("%d", &n);
        REP(i,0,n-1) scanf("%s", s[i]);
        int mx = (1<<n)-1;
        REP(i,0,mx) REP(j,0,n-1) if (i>>j&1) f[i][j].resize(1<<__builtin_popcount(i)-1);
        REP(i,0,n-1) f[1<<i][i][0] = 1;
        REP(i,1,mx) REP(j,0,n-1) if (i>>j&1) {
            int m = f[i][j].size()-1;
            REP(k,0,m) { 
                REP(x,0,n-1) if (i>>x&1^1) {
                    int nxt = k;
                    if (s[j][x]=='1') nxt ^= m+1;
                    f[i^(1<<x)][x][nxt] += f[i][j][k];
                }
                if (i==mx) ans[k] += f[i][j][k];
            }
        }
        mx = (1<<n-1)-1;
        REP(i,0,mx) printf("%lld ",ans[i]);hr;
    }
    View Code

    12. 1326F2

    大意: 1326F1的加强版


    $n$个人可以看成是一个无向图, 那么一个二进制数就对应图中的若干条链.

    例如$111000111011$对应链的长度集合为${ 4,1,1,4,3}$.

    那么可以发现只要对应的链的长度集合相同, 答案就相同.

    这个集合就相当于是$n$的整数拆分, $n=18$时, 拆分方案有$385$种.

    那么只要暴搜出所有拆分, 求出每个拆分的答案即可.

    对于一个拆分, 必须要保证相邻两条链之间是没有边的, 这个比较难处理.

    比方说要求${1,1,2}$的答案, 会把${1,3},{2,2},{4}$的答案也算上.

    可以注意到${1,1,2},{1,3},{2,2},{4}$对应的二进制数是$001,011,101,111$.

    也就是说${1,1,2}$刚好是其他多算的二进制数的子集.

    所以先求出不考虑相邻链是否有边的答案, 最后再做一次$IFWT_{and}$即可.

    先用$dp$求出$f_{len,S}$表示长$len$,状态为$S$的链的条数.

    那么可以得到拆分$T$的答案就为$sumprod f_{T_i,m_i}$

    $m_i$是第$i$条链的状态, 并且$m_1,...,m_{|T|}$的二进制或和等于$2^{n}-1$. (因为$T_i$的和一定为$n$,就不用考虑$m_i$交叉的情况)

    这个式子显然是$f_{T_i}$的集合并卷积的第$2^{n}-1$项, 可以用$FWT_{or}$求出.

    总复杂度为$O((385 n+n^2)2^n)$

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
     
     
    const int N = 18;
    int n, cnt;
    ll dp[1<<N][N],f[N+1][1<<N],h[1<<N],d[400],ans[1<<N];
    char a[N][N];
    map<vector<int>,int> ID;
    vector<int> g[400],v;
     
    void dfs(int d, int s) {
        if (s>n) return;
        if (s==n) {
            ID[v] = ++cnt;
            g[cnt] = v;
            return;
        }
        REP(i,d,n) v.pb(i),dfs(i,s+i),v.pop_back();
    }
     
    void FWT_or(ll *a, int n, int tp) {
        int mx = (1<<n)-1;
        REP(i,0,n-1) REP(j,0,mx) {
            if (j>>i&1) a[j]+=tp*a[j^1<<i];
        }
    }
    void FWT_and(ll *a, int n, int tp) {
        int mx = (1<<n)-1;
        REP(i,0,n-1) REP(j,0,mx) {
            if (j>>i&1) a[j^1<<i]+=tp*a[j];
        }
    }
     
    int main() {
        scanf("%d", &n);
        REP(i,0,n-1) scanf("%s",a[i]);
        dfs(1,0);
        REP(i,0,n-1) dp[1<<i][i] = 1;
        int mx = (1<<n)-1;
        REP(i,0,mx) {
            REP(j,0,n-1) if (i>>j&1) REP(k,0,n-1) if (i>>k&1^1) {
                if (a[j][k]=='1') dp[i^1<<k][k] += dp[i][j];
            }
            int len = __builtin_popcount(i);
            REP(j,0,n-1) f[len][i] += dp[i][j];
        }
        REP(i,1,n) FWT_or(f[i],n,1);
        REP(i,1,cnt) {
            REP(j,0,mx) h[j] = 1;
            for (int j:g[i]) REP(k,0,mx) h[k]*=f[j][k];
            FWT_or(h,n,-1);
            d[i] = h[mx];
        }
        mx = (1<<n-1)-1;
        REP(i,0,mx) {
            v.clear();
            REP(j,0,n-1) {
                int k = j;
                while (k<n-1&&(i>>k&1)) ++k;
                v.pb(k-j+1);
                j = k;
            }
            sort(v.begin(),v.end());
            ans[i] = d[ID[v]];
        }
        FWT_and(ans,n-1,-1);
        REP(i,0,mx) printf("%lld ", ans[i]);hr;
    }
    View Code

    13. 1327F

    大意: 长$n$的序列, 每个元素范围$[0,2^{k}-1]$, 给定$m$个限制$(l_i,r_i,x_i)$, 表示$a_l,...a_r$的二进制与和等于$x$, 求有多少种方案. 


    单独考虑二进制每位的答案, 假设$x_i$当前位为$0$, 那么就要求$[l_i,r_i]$中至少有$1$个$0$, 假设$x_i$当前位为$1$, 那么就要求$[l_i,r_i]$必须全为$1$. 那么枚举$1$和$0$的上次出现位置, 很容易写出$O(kn^2)$的$dp$.

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 998244353, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    const int N = 1e5+10;
    int n,k,m,l[N],r[N],x[N];
    vector<pii> f[N];
    int dp[2][2][N];
    void add(int &a, int b) {a+=b;if (a>=P)a-=P;}
    
    int solve(int d) {
        REP(i,1,n) f[i].clear();
        REP(i,1,m) f[r[i]].pb(pii(l[i],x[i]>>d&1));
        int cur = 0;
        memset(dp[cur],0,sizeof dp[0]);
        dp[0][0][0] = 1;
        //dp[i][z][j]
        //z = 0, 表示i填0, 上一个1的位置为j的方案数
        //z = 1, 表示i填1, 上一个0的位置为j的方案数
        REP(i,1,n) {
            cur ^= 1;
            memset(dp[cur],0,sizeof dp[0]);
            REP(j,0,i-1) REP(z,0,1) { 
                int &r = dp[!cur][z][j];
                add(dp[cur][z][j],r);
                add(dp[cur][!z][i-1],r);
            }
            for (auto &e:f[i]) {
                if (e.y==0) {
                    REP(j,0,e.x-1) dp[cur][1][j] = 0;
                }
                else {
                    REP(j,0,i-1) dp[cur][0][j] = 0;
                    REP(j,e.x,i-1) dp[cur][1][j] = 0;
                }
            }
        }
        int ans = 0;
        REP(i,0,n-1) REP(z,0,1) add(ans,dp[cur][z][i]);
        return ans;
    }
    
    int main() {
        scanf("%d%d%d",&n,&k,&m);
        REP(i,1,m) scanf("%d%d%d",l+i,r+i,x+i);
        int ans = 1;
        REP(i,0,k-1) ans = (ll)ans*solve(i)%P;
        printf("%d
    ", ans);
    }
    O(kn^2)代码

    然后考虑$O(kn)$的做法, 假设$f_i$表示第$i$个数取$0$的方案数, 如果从$f_j$转移到$f_i$的话, 也就是说$[j+1,i-1]$全填$1$, 那么合法的$j$必须大于等于所有满足$rle i-1$的$0$区间的$l$, 所以维护$0$区间的左端点最大值$ma$, 那么可转移的$j$的范围就是$[ma,i-1]$, 前缀优化一下即可. 对于$1$区间, 只要限制它覆盖的每个点$f_i$都为$0$即可. 这样复杂度就为$O(kn)$

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(_i,_a,_n) for(int _i=_a;_i<=_n;++_i)
    #define PER(_i,_a,_n) for(int _i=_n;_i>=_a;--_i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(_a) ({REP(_i,1,n) cout<<_a[_i]<<',';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 998244353, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    const int N = 1e6+10;
    int n,k,m,l[N],r[N],x[N],c[N],ma[N],f[N];
    void add(int &a, int b) {a=(a+b)%P;}
    
    int solve(int d) {
        REP(i,0,n+1) c[i] = ma[i] = f[i] = 0;
        REP(i,1,m) { 
            if (x[i]>>d&1) ++c[l[i]], --c[r[i]+1];
            else ma[r[i]] = max(ma[r[i]], l[i]);
        }
        REP(i,1,n) ma[i] = max(ma[i], ma[i-1]);
        f[0] = 1;
        int sum = 0;
        REP(i,1,n+1) {
            sum += c[i];
            if (!sum) f[i] = (f[i-1]-(ma[i-1]?f[ma[i-1]-1]:0))%P;
            add(f[i],f[i-1]);
        }
        return f[n+1]-f[n];
    }
    
    int main() {
        scanf("%d%d%d",&n,&k,&m);
        REP(i,1,m) scanf("%d%d%d",l+i,r+i,x+i);
        int ans = 1;
        REP(i,0,k-1) ans = (ll)ans*solve(i)%P;
        if (ans<0) ans += P;
        printf("%d
    ", ans);
    }
    O(kn)代码

    14. 1316F

  • 相关阅读:
    PAT B1045 快速排序 (25 分)
    PAT B1042 字符统计 (20 分)
    PAT B1040 有几个PAT (25 分)
    PAT B1035 插入与归并 (25 分)
    PAT B1034 有理数四则运算 (20 分)
    PAT B1033 旧键盘打字 (20 分)
    HDU 1231 最大连续子序列
    HDU 1166 敌兵布阵
    HDU 1715 大菲波数
    HDU 1016 Prime Ring Problem
  • 原文地址:https://www.cnblogs.com/uid001/p/12308235.html
Copyright © 2011-2022 走看看