hdu 6616 Divide the Stones

题意:将 重量为1到 n的物品  划分为k堆,每堆的个数相同 ,且重量相同。

思路:将相邻的k个物品分别分给k堆,可以想象成一个 ( n / k ) * k  的矩阵。注意到如果行数为偶数则很容易构造出来。如果为奇数行我们考虑 先 构造3行,再构造偶数行。三行的构造方法也很好想,感觉上就是轮换着构造。具体的可行性可通过循环群进行证明。

#include <bits/stdc++.h>
using namespace std;
typedef int lint;
typedef long long LL;
const lint maxk = 100001;
vector<lint> ve[maxk];
int main(){
    lint T,n,k;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        for( lint i = 1;i <= k;i++ )ve[i].clear();
        if( (n%k) || ((LL)n*(n+1)/2)%k ){
            puts("no");
            continue;
        }
        lint m = n/k;
        if( (LL)(1+k)*m % 2  ){
            puts("no");
            continue;
        }
        puts("yes");
        if( m%2  == 0){
            for( lint i = 1;i <= k;i++ ){
                lint s = i;
                bool first = true;
                for( lint j = 1;j <= m;j++ ){
                    if(first && j > m/2){
                        first = false;
                        s += (k+1)+(j-1)*k*2-s-s;
                    }
                    ve[i].push_back(s);
                    s += k;
                }
            }
            for( lint i = 1;i <=  k;i++ ){
                lint sum = 0;
                for( lint j = 0;j < m;j++ ){
                    printf("%d ",ve[i][j]);
                    sum += ve[i][j];
                }
                //printf("%d\n",sum);
                printf("\n");
            }
        }else{
            if( k == 1 ){
                for( lint i = 1;i <= n;i++ ){
                    printf("%d ",i);
                }
                printf("\n");
                continue;
            }
            lint a = 1,b = k/2+1;
            for( lint i = 1;i <= k;i++ ){
                ve[i].push_back(a);
                ve[i].push_back( b+k );
                ve[i].push_back( (LL)(3*k+1)*3*k/(2*k) - a - b - k );
                a++;b = b%k+1;
            }
            for( lint i = 1;i <= k;i++ ){
                lint s = i+3*k;
                bool first = true;
                for( lint j = 4;j <= m;j++ ){
                    if(first && j > (4+m)/2){
                        first = false;
                        s += (k+1)+(j-1)*k*2-s-s;
                    }
                    ve[i].push_back(s);
                    s += k;
                }
            }
            for( lint i = 1;i <= k;i++ ){
                lint sum = 0;
                for( lint j = 0;j < ve[i].size();j++ ){
                    printf("%d ",ve[i][j]);
                    sum += ve[i][j];
                }
                //printf("%d\n",sum);
                printf("\n");
            }
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值