A - Most Unstable Array
构造长为n,和为m的数组a,使得相邻元素差的绝对值之和最大。即,需要构造形如(0,x,0,0..)的数组。
- n == 1,ans = 0
- n == 2,ans = m
- n > 2,ans = 2 * m
B - Two Arrays And Swaps
a,b两数组将可以交换k次,最终使得a数组各元素和最大。将两数组排序,每次交换:若a中最小值小于b中最大值则交换,最后计算结果即可。
C - Board Moves
n*n个点,相邻的点之间可以移动,耗时为1,询问将所有点移动到一点需要的最短时间.
比赛时的解法:
- n为奇数时,其他点移动到中心点最优,模拟每一步的移动,计算。
- n为偶数, 中心点选择 x or y == n / 2中的一个点即可,处理同上。(emm,做的太急,题中规定:n is odd...)
- 以上两种情况画个图会很清楚的看出来选择方案。
官方:
选中中心点后,有8个点可以1步到达,16个点2步...
- ans = 1 * 8 + 2 * 16 + 3 * 24 + ... = 1 * 1 * 8 + 2 * 2 *8 + 3 * 3 * 8 + ...
- 循环计算n / 2次,每一次的i * i求和,最终结果 * 8.
D - Constructing the Array
一个全0数组,初始l = 1,r = n,每一步中选择最长的连续靠左全0区间。
-
第i步,r - l + 1为奇数,a[l + r >> 1] = i; 否则,a[l + r - 1 >> 1] = i;
-
使用优先队列存储各全0区间,其中r - l大的优先级最高,区间长度相等,l小的优先级高。
int mid,idx,t,n,a[kN];
//每次选择l r 最长全0序列 靠左
struct node{
int l,r;
friend bool operator < (node a,node b){//r - l大的优先级高
if((a.r - a.l) == (b.r - b.l)) return a.l > b.l;//靠左,l小优先级高
return (a.r - a.l) < (b.r - b.l);
}
}cur;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> t;
priority_queue<node> q;
while(t--){
cin >> n;
cur.l = 1,cur.r = n;
q.push(cur);
for(int i = 1; i <= n; i++){
cur = q.top();
q.pop();
idx = cur.r - cur.l + 1;
if(cur.r == cur.l){
a[cur.r] = i;
continue;
}
if(idx & 1){
mid = cur.r + cur.l >> 1;
a[mid] = i;
}
else{
mid = cur.l + cur.r - 1 >> 1;
a[mid] = i;
}
q.push({cur.l,mid - 1});
q.push({mid + 1,cur.r});
}
for(int i = 1; i <= n; i++){
if(i != 1) cout << ' ';
cout << a[i];
}
cout << endl;
while(!q.empty()) q.pop();
}
return 0;
}
E - K-periodic Garland
n个灯组成了一个环,等长字符串表示灯的状态 - '0': 关闭。'1':开启。如果每对相邻的灯之间距离为k,则称为k周期。(0010010,001001 均可以,001010001,1001等则不可以),如果花环不是k周期,寻找最少的灯的状态改变个数。 -- 01串修改为相邻两1之间有k - 1个0.
-
字符串分为k个周期子串,结果中的各个'1'的索引 mod k后的值相等。
-
'1'的位置选定后,其他位置的'1'修改为'0'。
-
先记录原字符串中1的个数sum,初始答案赋值为sum(存在000..x or 00...0这样的合法序列,若需要修改的次数大于之前1的个数,之前修改为全0,次数更少,answer最大为sum)
dp解法 -
dp(i,0 or 1)表示第i位为0 or 1时符合要求的最小操作次数,cnt[i]:前i位中,1的个数
-
dp(i,0) = min(dp(i - 1, 0),dp(i - 1, 1)) + s[i] != '0'
-
dp(i,1) = min(dp(i - k,1) + cnt( i - 1) - cnt[i - k],cnt[i - 1]) + s[i] != '1'//cnt[i - 1] - cnt[i - k] :(i - 1,i - k]中的1的个数,也可修改为00...01
cin >> n >> k >> s;
for(int i = 0; i < n; i++) cnt[i] = cnt[i - 1] + (s[i] - '0'),dp[i] = 0x3f3f3f3f;
for(int i = 0; i < n; i++){
if(i < k){
dp[i][1] = cnt[i - 1] + (s[i] == '0');//第一个周期,之前的1全部修改
dp[i][0] = min(dp[ i - 1][1],dp[i - 1][0]) + (s[i] == '1')
}else{
dp[i][1] = min(dp[i - k][1] + cnt[i - 1] - cnt[i - k],cnt[i - 1]) + (s[i] == '0');
dp[i][0] = min(dp[i - 1][1],dp[i - 1][1]) + (s[i] == '1');
}
}
cout << min(dp[n - 1][0],dp[n - 1][1]) << endl;