2020牛客暑期多校训练营(第六场)G

Description

(n imes n) 的网格图的边染 (k) 种颜色,每种颜色染的边数相同,构造不存在同色环,且没有某一整行或整列的颜色相同的方案数。

Solution

约定左上角的格点为 ((0,0)),由一个点 ((i,j)) 向右发出的边记做 ((i,j,0)),向下发出的边记做 ((i,j,1))

先考虑两种颜色时怎么放。

(n) 为偶数,则选取 (0,0,0),(0,2,0),(0,4,0),...,(1,1,0),(1,3,0),(1,5,0),...,(2,0,0),(2,2,0),(2,4,0),...,...,(0,0,1),(0,1,1),(0,2,1),...,(2,0,1),(2,1,1),(2,2,1),...,...,...

(n) 为奇数,则按 ((i,j,k))((i+j) mod 2) 定色。

考虑 (k) 种颜色且 (k) 为偶数时,我们将原先的黑色中任意分出若干个给 ([k/2-1]) 种新颜色,将原先的白色中任意分出若干个给另外 ([k/2-1]) 种新颜色。

(k) 为奇数时,我们需要分 (siz) 条边给多出来的那一种颜色,我们只需要从左半图中贪心地取若干条黑边,右半图中贪心地取若干白边,数量分别为 (frac {siz} {2}),然后再按 (k) 为偶数的情况继续执行即可。

#include<bits/stdc++.h>
using namespace std;

const int N = 205;
int f[N][N][2];

void solve(int n,int k)
{
    // Step 0
    for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) f[i][j][0]=f[i][j][1]=0;
    for(int i=0;i<=n;i++) f[n][i][1]=f[i][n][0]=-1;
    
    // Step 1
    if(n&1)
    {
        for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=0;k<2;k++) if(f[i][j][k]!=-1) f[i][j][k]=(i+j+1)%2;
    }
    else
    {
        for(int i=0;i<=n;i++) for(int j=i&1;j<n;j+=2) f[i][j][0]=1;
        for(int i=0;i<n;i+=2) for(int j=0;j<=n;j++) f[i][j][1]=1;
    }

    // Step 2
    if(k&1)
    {
        int c=k-1,tot=2*n*(n+1)/k,cnt=0;
        for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=1;k>=0;k--) if(f[i][j][k]==0 && cnt<tot/2) f[i][j][k]=c, ++cnt;
        for(int i=n;i>=0;i--) for(int j=n;j>=0;j--) for(int k=1;k>=0;k--) if(f[i][j][k]==1 && cnt>0) f[i][j][k]=c, --cnt;
    }

    // Step 3
    if(k>2)
    {
        int t=(k-2)/2,cnt=0,siz=2*n*(n+1)/k;
        for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=1;k>=0;k--)
        {
            int c=2+cnt/siz;
            if(c<=2+t-1)
            {
                if(f[i][j][k]==0) f[i][j][k]=c,++cnt;
            }
        }
        for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=1;k>=0;k--)
        {
            int c=2+cnt/siz;
            if(c<=2+2*t-1)
            {
                if(f[i][j][k]==1) f[i][j][k]=c,++cnt;
            }
        }
    }
    
    // Output
    for(int i=0;i<=n;i++) 
    {
        for(int j=0;j<n;j++) printf("%d ",f[i][j][0]+1);
        puts("");
    }
    for(int i=0;i<=n;i++) 
    {
        for(int j=0;j<n;j++) printf("%d ",f[j][i][1]+1);
        puts("");
    }

    
}

int T,n,k;

bool TP()
{
    if(n==1||k<=1||2*(n+1)*n%k!=0)
    {
        printf("-1
"); 
        return true;
    }
    if(n==2&&k==3)
    {
        printf("1 2
");
        printf("3 1
");
        printf("3 2
");
        printf("1 3
");
        printf("2 1
");
        printf("2 3
");
        return true;
    }
    if(n==3&&k==3)
    {
        printf("1 2 3
");
        printf("2 3 2
");
        printf("1 3 1
");
        printf("3 1 2
");
        printf("3 2 1
");
        printf("3 1 2
");
        printf("1 2 3
");
        printf("2 1 3
");
        return true;
    }
    return false;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        if(!TP()) solve(n,k);
    }
    return 0;
}

// Checker
    /*map<int,int> mp;
    for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) 
    {
        mp[f[i][j][0]]++;
        mp[f[i][j][1]]++;
    }
    int siz=2*n*(n+1)/k;
    for(auto i:mp) if(i.first>=0) if(i.second!=siz) cout<<"FAILED A"<<endl;

    for(int i=0;i<=n;i++) for(int j=0;j<=n;j++)
    {
        if(f[i][j][0]==f[i][j+1][0] && j+1<=n) cout<<"FAILED B"<<endl;
        if(f[i][j][1]==f[i+1][j][1] && i+1<=n) cout<<"FAILED B"<<endl;
    }

    for(int i=0;i<n;i++) for(int j=0;j<n;j++)
    {
        set<int> s;
        s.insert(f[i][j][0]);
        s.insert(f[i][j][1]);
        s.insert(f[i+1][j][0]);
        s.insert(f[i][j+1][1]);
        if(s.size()==1) cout<<"FAILED C"<<endl;
    }*/
原文地址:https://www.cnblogs.com/mollnn/p/13773810.html