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

  • 相关阅读:
    C#-使用Tuple传递多个参数
    CentOS 常用命令
    C#-ToString格式化
    java面对对象(六)--内部类、匿名内部类
    JAVA面对对象(五)——接口
    JAVA面对对象(四)——抽象类
    JAVA面对对象(三)——Super、static、final关键字
    Mybatis缓存
    重启博客
    某大神的装修笔记
  • 原文地址:https://www.cnblogs.com/uid001/p/12308235.html
Copyright © 2011-2022 走看看