20231016比赛总结

比赛链接

反思

B

感觉有点难想,而且要特判!

C

没想到正解并不算太难

题解

A

没什么好说的,之前做过类似的题
时间复杂度 O ( n ln ⁡ n ) O(n\ln n) O(nlnn)

#include 
using namespace std;
const int N=1000100;
int n,siz[N],sum[N];
int e[N<<1],ne[N<<1],h[N],idx;
inline int read(){
    int FF=0,RR=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    return FF*RR;
}
void dfs(int u,int fa){
    siz[u]=1;
    for(int i=h[u];~i;i=ne[i]){
        int v=e[i];if(v==fa) continue;
        dfs(v,u),siz[u]+=siz[v];
    }
}
void add(int x,int y){ e[idx]=y,ne[idx]=h[x],h[x]=idx++;}
int main(){
    freopen("eat.in","r",stdin);
    freopen("eat.out","w",stdout);
    n=read();
    memset(h,-1,sizeof(h));
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        add(x,y),add(y,x);
    }
    dfs(1,-1);
    for(int i=1;i<=n;i++){
        int g=siz[1]/__gcd(siz[1],siz[i]);
        for(int j=g;j<=n;j+=g) sum[j]++;
    }
    int ans=0;
    for(int i=1;i<=n;i++)
        if(siz[1]%i==0) if(sum[i]>=i) ans++;
    printf("%d\n",ans);
    fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
    return 0;
}

B

有些神的题
首先考虑 d p dp dp
但状态不好表示
我们想到这是一张每个点出度为 1 1 1 的图,那么前 i i i 个点一定会构成若干条链,那么我们不妨记 d p i , j dp_{i,j} dpi,j 为前 i i i 个点,构成了 j j j 条链的方案数
转移的话对当前点是 L 还是 R 分类讨论即可
询问 i i i 的答案的话合并前缀和后缀的 d p dp dp 数组即可
时间复杂度 O ( n 2 ) O(n^2) O(n2)

#include 
using namespace std;
const int N=5100,P=1e9+7,inv2=500000004;
int n,fac[N],f[N][N],g[N][N];
char str[N];
inline int read(){
    int FF=0,RR=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    return FF*RR;
}
int main(){
    freopen("jump.in","r",stdin);
    freopen("jump.out","w",stdout);
    n=read();scanf("%s",str+1);
    if(n==1){ puts("1");exit(0);}
    f[0][0]=1;
    for(int i=1;i<=n;i++){
        if(str[i]=='L')
            for(int j=1;j<=i;j++)
                f[i][j]=(1ll*f[i-1][j+1]*(j+1)%P*j+1ll*f[i-1][j]*j)%P;
        else
            for(int j=1;j<=i;j++)
                f[i][j]=(f[i-1][j-1]+1ll*f[i-1][j]*j)%P;
    }
    g[n+1][0]=1;
    for(int i=n;i;i--){
        if(str[i]=='R')
            for(int j=1;j<=n-i+1;j++)
                g[i][j]=(1ll*g[i+1][j+1]*(j+1)%P*j+1ll*g[i+1][j]*j)%P;
        else
            for(int j=1;j<=n-i+1;j++)
                g[i][j]=(g[i+1][j-1]+1ll*g[i+1][j]*j)%P;
    }
    fac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%P;
    printf("%d ",g[2][1]);
    for(int i=2;i<n;i++){
        int ans=0;
        for(int j=1;j<i;j++){
            int coef1=1ll*f[i-1][j]*g[i+1][j+1]%P*fac[j+1]%P*fac[j]%P;
            int coef2=1ll*f[i-1][j]*g[i+1][j]%P*fac[j]%P*fac[j]*2%P;
            int coef3=1ll*f[i-1][j]*g[i+1][j-1]%P*fac[j]%P*fac[j-1]%P;
            ans=(1ll*ans+coef1+coef2+coef3)%P;
        }
        printf("%d ",ans);
    }
    printf("%d\n",f[n-1][1]);
    fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
    return 0;
}

C

我们考虑如何判断一个子矩形不存在两个黑色连通块(假设我们保证它不存在空腔)
我们把每列中极大的黑色相邻块缩成一个点,然后列与列直接相邻的点之间连边
如果这个图是一颗树,即 ∣ V ∣ = ∣ E ∣ + 1 |V|=|E|+1 V=E+1,那么它就合法

我们考虑搜出所有的空腔的,然后在 ( x 2 + 1 , y 2 + 1 ) (x_2+1,y_2+1) (x2+1,y2+1) y 1 − 1 y_1-1 y11 t a g tag tag,不难发现直接双指针 + 桶维护即可
时间复杂度 O ( n 3 ) O(n^3) O(n3)

#include 
#define pb push_back
using namespace std;
typedef long long LL;
const int N=310;
int n,m,mnx,mny,mxx,mxy;
char str[N];
bool a[N][N],vis[N][N];
struct Node{ int x1,x2,y1,y2;};
vector<Node> tag[N];
vector<int> tg[N][N];
int fx[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
inline int read(){
    int FF=0,RR=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    return FF*RR;
}
void dfs(int x,int y){
    mnx=min(mnx,x),mny=min(mny,y),mxx=max(mxx,x),mxy=max(mxy,y);
    vis[x][y]=1;
    for(int k=0;k<4;k++){
        int tx=x+fx[k][0],ty=y+fx[k][1];
        if(tx<1||tx>n||ty<1||ty>m||a[tx][ty]||vis[tx][ty]) continue;
        dfs(tx,ty);
    }
}
int buc[N*N],totV[N],totE[N],B[N];
int main(){
    freopen("village.in","r",stdin);
    freopen("village.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        scanf("%s",str+1);
        for(int j=1;j<=m;j++) a[i][j]=str[j]-48;
    }
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!a[i][j]&&!vis[i][j]&&(i==1||i==n||j==1||j==m)) dfs(i,j);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!a[i][j]&&!vis[i][j]){
        mnx=1e9,mny=1e9,mxx=0,mxy=0;
        dfs(i,j);
        tag[mnx-1].pb({mnx,mxx,mny,mxy});
    }
    int Delta=n+5;
    LL ans=0;
    for(int u=n;u>=1;u--){
        for(Node t:tag[u]) tg[t.x2+1][t.y2+1].pb(t.y1-1);
        memset(totV,0,sizeof(totV));
        memset(totE,0,sizeof(totE));
        memset(B,0,sizeof(B));
        for(int d=u;d<=n;d++){
            for(int i=1;i<=m;i++)
                if(a[d][i]&&(d==u||!a[d-1][i])){
                    totV[i]++;
                    if(a[d][i-1]) totE[i]++;
                    if(a[d][i+1]&&!(d==u||!a[d-1][i+1])) totE[i+1]++;
                }
            for(int i=1;i<=m;i++) totV[i]+=totV[i-1],totE[i]+=totE[i-1];
            buc[totV[0]-totE[1]+Delta]++;
            assert(totV[0]-totE[1]+Delta>=0),assert(totV[0]-totE[1]+Delta<(N<<1));
            for(int i=1,j=0;i<=m;i++){
                for(int t:tg[d][i]) B[i]=max(B[i],t);
                while(j<B[i]){ buc[totV[j]-totE[j+1]+Delta]--;j++;}
                assert(totV[i]-totE[i]-1+Delta>=0),assert(totV[i]-totE[i]-1+Delta<N*N);
                ans+=buc[totV[i]-totE[i]-1+Delta];
                if(i<m){
                    assert(totV[i]-totE[i+1]+Delta>=0),assert(totV[i]-totE[i+1]+Delta<N*N);
                    buc[totV[i]-totE[i+1]+Delta]++;
                }
            }
            for(int i=0;i<m;i++) buc[totV[i]-totE[i+1]+Delta]=0;
            for(int i=m;i;i--) totV[i]-=totV[i-1],totE[i]-=totE[i-1];
            for(int i=1;i<=m;i++) B[i]=max(B[i],B[i-1]);
        }
    }
    printf("%lld\n",ans);
    fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
    return 0;
}

你可能感兴趣的:(其他,图论)