直接贪心的做法是不对的(例如: 23 6 , 27 7 , 28 7, 31 8 等...)
多校的时候因为SPJ的问题很多WA的程序都过了,实际上这题并没有那么水......
无解的有两种情况 1: sum不能被m整除 2: sum/m比n小
剩下的情况都有解:
标程的做法是根据: n(n+1)/(2*m) 每一组里都有k对组合,如第一行中的(11 100) (12 99) (13 98)....
因为有m行所以这样的组合有2*k*m个,这些对都可以凑成一样的大小
剩下的为粉红色的部分, 这些数字有(n-(2*m-1))%(2*m)+(2*m-1)个 (如样例 1~10),然后对这部分进行从大到小的贪心.....(感觉还是有问题???....)
n=100,m=5的数据
100 5
YES
20 10 1 11 100 12 99 13 98 14 97 15
96 16 95 17 94 18 93 19 92
20 9 2 20 91 21 90 22 89 23 88 24
87 25 86 26 85 27 84 28 83
20 8 3 29 82 30
81 31 80 32 79 33 78 34 77 35 76
36 75 37 74
20 7 4 38 73 39
72 40 71 41 70 42 69 43 68 44 67
45 66 46 65
20 6 5 47 64 48
63 49 62 50 61 51 60 52 59 53 58 54 57 55 56
参考题解: http://blog.csdn.net/queuelovestack/article/details/47321211
4 1 2 5 3 5 2 9 3
NO YES 1 5 2 1 4 2 2 3 NO YES 3 1 5 9 3 2 6 7 3 3 4 8
/* ***********************************************
Author :CKboss
Created Time :2015年08月07日 星期五 14时23分36秒
File Name :HDOJ5355_2.cpp
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long int LL;
LL n,m;
vector<int> vi[10];
set<int> v;
void init()
{
for(int i=0;i<10;i++) vi[i].clear();
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T_T;
scanf("%d",&T_T);
while(T_T--)
{
cin>>n>>m;
init();
LL sum=n*(n+1)/2;
if(sum%m||n+1<2*m)
{
puts("NO"); continue;
}
LL c=(n-m*2+1)%(m*2)+m*2-1;
v.clear();
for(int i=1;i<=c;i++)
{
v.insert(i);
}
LL s=c*(c+1)/(m*2);
for(int i=0;i<m;i++)
{
set<int>::iterator it;
LL ts=0;
while(ts<s)
{
it=v.upper_bound(s-ts);
LL tmp=*--it;
vi[i].push_back(tmp);
ts+=tmp;
v.erase(it);
}
}
int st=c+1;
int ed=n;
int k=(n-c)/(2*m);
for(int i=0;i<m;i++)
{
for(int j=0;j<k;j++)
{
vi[i].push_back(st); st++;
vi[i].push_back(ed); ed--;
}
}
puts("YES");
for(int i=0;i<m;i++)
{
int sz=vi[i].size();
printf("%d",sz);
for(int j=0;j<sz;j++)
{
printf(" %d",vi[i][j]);
}
putchar(10);
}
}
return 0;
}
标程的代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int sol(){
int n,m;
scanf("%d%d",&n,&m);
if(((n+1ll)*n>>1)%m!=0 || m * 2 -1 > n) return puts("NO");
const int c=(n+1-m*2)%(m*2)+m*2-1,
s=c*(c+1)/(m*2),
d=(n-c)/(m*2);
puts("YES");
set<int> v;
for(int i=1;i<=c;++i)v.insert(i);
for(int j=0,l=c+1;j<m;++j,putchar('\n')){
static int o[32],c,r;
for(c=r=0;r<s;){
auto it = v.upper_bound(s-r);
r+=o[c++]=*--it;
v.erase(it);
}
printf("%d",c+d*2);
for(int i=0;i<c;++i)printf(" %d",o[i]);
for(int i=0;i<d;++i)printf(" %d %d",l++,n--);
}
}
int main(){
int T;
for(scanf("%d",&T);T--;sol());
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文:http://blog.csdn.net/ck_boss/article/details/47341215