CF1119G. Get Ready for the Battle
题目描述
Solution
妙妙构造题。
考虑这样一个过程:所有人一起打第一个怪,每次打nnn,最后剩下k1<nk_1<nk1<n,就找一些加起来正好为k1k_1k1的组打掉k1k_1k1,剩下的n−k1n-k_1n−k1打第二个怪,然后重复打nnn,余数k2k_2k2找一些组正好打掉这样一个过程,直到剩下最后一个怪,打玩n−km−1n-k_{m-1}n−km−1,再一直打nnn到非正。
若能够构造s1..ms_{1..m}s1..m,满足可以配成k1...km−1k_1...k_{m-1}k1...km−1中的任意数。
即可求出答案为⌈∑ain⌉\lceil \frac{\sum a_i}{n} \rceil⌈n∑ai⌉。
于是我们将kkk排序,令si=ki+1−kis_i=k_{i+1}-k_{i}si=ki+1−ki,sm=n−km−1s_m=n-k_{m-1}sm=n−km−1,可以满足任意kik_iki为sss前缀和中的一个。
构造完sis_isi之后,事实上只需要用a1a_1a1依次减s[1...m]s[1...m]s[1...m],减完s[m]s[m]s[m]之后再从s[1]s[1]s[1]开始减。若减的过程中a1≤0a_1\leq 0a1≤0,则用a2a_2a2继续减,直到am≤0a_m\leq 0am≤0。
事实上这样做,a1..(m−1)a_{1..(m-1)}a1..(m−1)都会减为0,达到最优解。
原因参照下例:
a1−n−n−...−n−k1=0a_1-n-n-...-n-k_1=0a1−n−n−...−n−k1=0
a2−(n−k1)%n−n−n−...−n−k2=0a_2-(n-k1)\%n-n-n-...-n-k_2=0a2−(n−k1)%n−n−n−...−n−k2=0
a3−(n−k2)%n−n−n−...−n−k3=0a_3-(n-k2)\%n-n-n-...-n-k_3=0a3−(n−k2)%n−n−n−...−n−k3=0
..................
am−(n−km−1)%n−n−n−...−n≤0a_m-(n-k_{m-1})\%n-n-n-...-n\leq0am−(n−km−1)%n−n−n−...−n≤0
kik_iki与(n−ki)(n-k_i)(n−ki)配成一段连续的s[1..m]s[1..m]s[1..m]。
且不可能出现如下情况:
a1−n−n−...−n−k1=0a_1-n-n-...-n-k_1=0a1−n−n−...−n−k1=0
a2−k2=0(a2<(n−k1)%n)a_2-k_2=0\;\;(a_2<(n-k1)\%n)a2−k2=0(a2<(n−k1)%n)
..................
因为k2=(a1+a2)%nk_2=(a_1+a_2)\%nk2=(a1+a2)%n,因此k2=(k1+k2)%nk_2=(k_1+k_2)\%nk2=(k1+k2)%n,则k1%n=0k_1\%n=0k1%n=0,则k1=0k_1=0k1=0。
因此按此过程一定是按s[1..m]s[1..m]s[1..m]连续减下去,减完s[m]s[m]s[m],从s[1]s[1]s[1]继续减下去。
Code(讲述凌乱,理解代码体验极佳)
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se secondusing namespace std;template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int MAXN=1000005;
const ll INF=1ll<<60;
/*--------------------------------------------------------------------*/
inline int read()
{int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f;
}
VI Ans;
int a[MAXN],b[MAXN],s[MAXN];
int main()
{int n=read(),m=read(),sum=0; b[1]=n;for (int i=1;i<=m;i++) sum+=(a[i]=read()),b[i+1]=sum%n;sort(b+1,b+m+1);for (int i=1;i<=m;i++) s[i]=b[i]-b[i-1];for (int i=1,id=0;i<=m;i++){int t=a[i];while (t>0) Ans.PB(i),t-=s[id%m+1],id++;}printf("%d\n",(sum-1)/n+1);while (Ans.size()%m) Ans.PB(1);for (int i=1;i<=m;i++) printf("%d%c",s[i]," \n"[i%m==0]);for (int i=0;i<Ans.size();i++) printf("%d%c",Ans[i]," \n"[(i+1)%m==0]);return 0;
}