http://codeforces.com/problemset/problem/899/C
题意:给你1~n连续的n个数。将这n个数分成两拨,要求两拨之差的绝对值k最小。求出这个最小的绝对值,并输出其中的一拨的数字。
题解:首先要想清楚这个k非零即一。
先将问题分解成两类:奇数和偶数。
先看最简单的偶数:
由于可以组成如1,n以及2,n-1这样的数对。
①如果n%4==0。那么就有偶数组上述数对,直接构造输出即可。k就等于0。
②如果n%4!=0。那么两拨分完之后还剩下一个上述数对,那么一拨一个。很容易想到要剩下的是n/2和n/2+1。那么k等于1。
在看奇数:
①如果(n+1)%4==0。那么k=0。为什么?
以n=7为例,在分好1,7,2,6和3,5,4之后。相当于这两拨的差距在2,6和4。第一拨多了n+1,第二拨多了(n+1)/2。也就是说第一拨比第二拨多了(n+1)/2。那么第一拨就要分出(n+1)/4给第二拨(这也是为什么要满足(n+1)%4==0)。可以发现就是要交换上面的6和4,让2和4凑成一对,这样(n+1)/4和(n+1)/2凑成一对。这样k等于0。
②如果n%4!=0。那么k就不会等于0了,那么肯定存在k=1的解。
以5为例,分成1,5和2,4,3。这里是1和3互换,原理同上。
代码:
#include<bits/stdc++.h>
#define debug cout<<"aaa"<<endl
#define d(a) cout<<a<<endl
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define MIN_INT (-2147483647-1)
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807i64
#define MIN_LL (-9223372036854775807i64-1)
using namespace std;
const int N = 100000 + 5;
const int M = N * N + 5;
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
int main(){
int n;
if(n%2==0){
if(n%4==0){
cout<<0<<endl;
cout<<n/4*2<<" ";
for(int i=1;i<=n/4;i++){
cout<<i<<" "<<n-i+1<<" ";
}
cout<<endl;
}
else{
cout<<1<<endl;
cout<<n/4*2+1<<" ";
for(int i=1;i<=n/4;i++){
cout<<i<<" "<<n-i+1<<" ";
}
cout<<n/2<<endl;
}
}
else{
if((n+1)%4==0){
cout<<0<<endl;
cout<<(n+1)/4*2<<" ";
for(int i=1;i<=(n+1)/4;i++){
if((n+1)/4==i){
cout<<i<<" "<<(n+1)/2<<" ";
}
else{
cout<<i<<" "<<n-i+1<<" ";
}
}
cout<<endl;
}
else{
cout<<1<<endl;
cout<<(n+1)/4*2<<" ";
for(int i=1;i<=(n+1)/4;i++){
if((n+1)/4==i){
cout<<(n+1)/2<<" "<<n-i+1<<" ";
}
else{
cout<<i<<" "<<n-i+1<<" ";
}
}
cout<<endl;
}
}
return 0;
}