codeforces 补题1
题目:D. Retaliation
https://codeforces.com/contest/2117/problem/D
大意:
在一次操作中,可以完成以下两项操作之一:
- 对于 a 中的每个索引 i ,将 ai 减少 i 。
- 对于 a 中的每个索引 i ,将 ai 减少 n−i+1 。
判断是否能使数组中的每一个元素都等于0,如果可以,输出“Yes”,反之输出“No”.
思路:
这是一道数学题,假设要使数组中的每一个元素都等于0需要执行“操作1”x次,“操作2”y次,因为每个元素都等于0,所以数组前两个元素一定等于0,数组前两个元素的值均已知,列出方程组可以解出x和y的值,判断x和y的值是否合理,是否也能使其他元素都等于0。
代码:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
using ll = long long;
void solve() {int n; cin >> n;vector<int>nums(n + 1, 0);for (int i = 1; i <= n; i++) {cin >> nums[i];}int yj = (2 * nums[1] - nums[2]) % (n + 1);if (yj != 0) {//判断x和y是否能被整除cout << "NO" << endl;return;}int y= (2 * nums[1] - nums[2]) / (n + 1);int x = y - nums[1] + nums[2];//利用nums[1]和nums[2]表示x和y的值if (x < 0 || y < 0) {//如果x或者y小于0,则该值不合理,输出Nocout << "NO" << endl;return;}for (int i = 3; i <= n; i++) {//检查除nums[1]和nums[2]以外,其他元素是否也等于0if (nums[i] - x * i - y * (n - i + 1) != 0) {cout << "NO" << endl;return;}}cout << "YES" << endl;return;
}signed main() {int t; cin >> t;while (t--)solve();return 0;
}/*如果题目是对一个数组同时进行某些操作,就可以从部分入手,先利用部分已知量来表示未知量,
然后把表示出来的未知量套入数组中观察是否数组中的每一个元素都符合条件。*/
题目:B. Skibidus and Fanum Tax (hard version)
https://codeforces.com/contest/2065/problem/C2
大意:
给定数组a,b,能否对数组a任意元素进行操作,使得得到的数组a,非递减排列,即对于任意的i都满足a[i]<=a[i+1],若能满足输出“YES”,反之输出“NO”。
对数组a进行的操作:a[i]=b[j]-a[i],其中j为b数组任意一个元素的下标。
思路:
若想使a[i]<=a[i+1],成立,a[i+1]应该在不超过a[i+2]的范围的条件下取得最大值,这样a[i]的条件才能更加宽松。首先先对b数组从小到大进行排序,如果是a数组的最后一个元素a[n-1]想取最大值,a[n-1]=max(a[n-1],b[m-1])。如果不是最后一个元素有以下几种情况:
1.如果找不到b[j]使得b[j]-a[i]为不大于a[i+1]的最大值(找不到最大的b[j]使得b[j]-a[i]<=a[i+1]),并且a[i]>a[i+1],这种情况出现,数组不可能按照非递减排列。
2.如果能找到最大的b[j]使得b[j]-a[i]<=a[i+1],并且a[i]>a[i+1],这时候的a[i]只能为b[j]-a[i];
3.如果能找到最大的b[j]使得b[j]-a[i]<=a[i+1],并且a[i]<a[i+1],这时候a[i]=max(b[j]-a[i],a[i]),取较大的数,为下一次比较铺路。
代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#include<numeric>
#include<limits>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<iomanip>
#include<sstream>
using namespace std;
using ll = long long;
void solve() {
//输入int n, m;cin >> n >> m;vector<ll>a(n), b(m);for (int i = 0; i < n; i++)cin >> a[i];for (int j = 0; j < m; j++)cin >> b[j];
//对b按从小到大排序sort(b.begin(), b.end());
//对a[n-1]进行特殊处理,取最大值。a[n - 1] = max(b[m - 1] - a[n - 1], a[n - 1]);
//对其他元素进行处理for (int i = n - 1; i > 0; i--) {
//upper_bound()函数用于寻找不大于a[i]+a[i-1]的最大b[j],注意下标应该-1。int k = upper_bound(b.begin(), b.end(), a[i] + a[i - 1]) - b.begin();
//情况1:找不到b[j],并且前一个大于后一个。if (!k && a[i - 1] > a[i]) {cout << "NO" << endl;return;}
//情况2:找到b[j],并且前一个不大于后一个。else if (k && a[i - 1] <= a[i]) {a[i - 1] = max(a[i - 1], b[k - 1] - a[i-1]);}
//情况3:找到b[j],并且前一个大于后一个。else if (k && a[i - 1] > a[i]) {a[i - 1] = b[k - 1] - a[i-1];}}cout << "YES" << endl;return;}
signed main() {int t; cin >> t;while (t--)solve();return 0;
}
题目:D. Skibidus and Sigma
https://codeforces.com/contest/2065/problem/D
大意:
给定一个二维数组,对数组的每行进行排序,使得其前缀和相加为最大值。
例如:数组:{(4,4),(6,1)}
- 按{4,4,6,1}排列 ,它的得分是 4+(4+4)+(4+4+6)+(4+4+6+1)=41 。
- 按{6,1,4,4}排列, 它的得分是 6+(6+1)+(6+1+4)+(6+1+4+4)=39 。
思路:
贪心,对每一行的所有值求和,按照总和从大到小进行排序。然后按题目要求相加即可。
代码:
#include<iostream>
#include<algorithm>
#include<vector>
#include<numeric>
#include<set>
#include<map>
#include<iomanip>
#include<limits>
#include<string>
#include<cstring>
using namespace std;
using ll = long long;//排序规则
bool cmp(vector<ll>& arr1, vector<ll>& arr2) {//注意这里传递参数传的是数组ll sum = accumulate(arr1.begin(), arr1.end(), 0);ll sum1 = accumulate(arr2.begin(), arr2.end(), 0);return sum > sum1;
}void solve() {
//输入ll n, m; cin >> n >> m;vector<vector<ll>>nums(n, vector<ll>(m, 0));for (ll i = 0; i < n; i++) {for (ll j = 0; j < m; j++) {cin >> nums[i][j];}}
//排序sort(nums.begin(), nums.end(), cmp);vector<ll>sum_nums(n * m + 1, 0);ll k = 1;for (ll i = 0; i < n; i++) {for (ll j = 0; j < m; j++) {sum_nums[k] = sum_nums[k - 1] + nums[i][j];//前缀和k++;} }
//将前缀和相加,注意这里accumulate()的使用,accumulate(x.begin(),x.end(),0),这里的0默认是int类型,需要强制转换成ll。ll ans = accumulate(sum_nums.begin(), sum_nums.end(), (ll)0);cout << ans << endl;}
signed main() {ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);int t; cin >> t;while (t--)solve();return 0;
}
题目:E. Skibidus and Rizz
https://codeforces.com/contest/2065/problem/E
大意:
给定0的数量是n,1的数量是m,和k,输出一个字符串使得它的全部字串的max(n-m,m-n)最大值为k。
思路:
思考题,字符串开头用数量多的(0||1)直接填满k,之后10交替就行。
代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<numeric>
#include<limits>
#include<string>
#include<iomanip>
#include<map>
#include<set>
#include<sstream>
#include<cmath>
using namespace std;
using ll = long long;
void solve() {int n, m, k; cin >> n >> m >> k;string str;
//如果k比n,m都大,直接-1。 如果k比abs(n-m)小,直接-1。if ((k > m && k > n)||(n-m>k)||(m-n>k)) {cout << -1 << endl;return;}else {if (m >= n) {for (int i = 0; i < k; i++) {str += '1';}m -= k;while (m > 0 || n > 0) {if (n > 0) {str += '0';n--;}if (m > 0) {str += '1';m--;}}}else if (m < n) {for (int i = 0; i < k; i++) {str += '0';}n -= k;while (m > 0 || n > 0) {if (m > 0) {str += '1';m--;}if (n > 0) {str += '0';n--;}}}}cout << str << endl;
}
signed main() {int t; cin >> t;while (t--)solve();return 0;
}
题目:C. Sakurako's Field Trip
https://codeforces.com/contest/2033/problem/C
大意:
给定一个数组a,可以进行将索引i和索引n-i+1对应的元素交换,能否通过任意次交换使得a[i]==a[i+1]的次数最少,输出最少次数。
思路:
双指针,看见相等就交换,要不就相等的数量不变,要不数量减一
代码:
#include<iostream>
#include<algorithm>
#include<vector>
#include<numeric>
#include<limits>
#include<sstream>
#include<iomanip>
#include<map>
using namespace std;
using ll = long long;
void solve() {int n; cin >> n;vector<ll>nums(n);for (int i = 0; i < n; i++)cin >> nums[i];int left = 1; int right = n - 2;while (left < right) {if (nums[left - 1] == nums[left] || nums[right + 1] == nums[right]) {swap(nums[left], nums[right]);}left++;right--;}int ans = 0;for (int i = 0; i < n-1; i++) {if (nums[i] == nums[i + 1]) {ans++;}}cout << ans << endl;
}
signed main() {int t; cin >> t;while (t--)solve();return 0;
}
题目:D. Kousuke's Assignment
https://codeforces.com/contest/2033/problem/D
大意:
如果有 al+al+1+⋯+ar−1+ar=0 ,则 [l,r] 段被认为是美丽的,计算不重叠的美丽线段的最大数目。
思路:
用map记录每一步sum的值,如果这个值之前遇到过就说明有一段a的元素相加等于0,这时候清空map,如果不清空就会重叠。
代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<limits>
#include<numeric>
#include<cmath>
using namespace std;
using ll = long long;
void solve() {int n; cin >> n;vector<ll>nums(n, 0);for (int i = 0; i < n; i++)cin >> nums[i];map<ll, int>mp;ll sum = 0;int ans = 0;for (int i = 0; i < n; i++) {sum += nums[i];if (mp[sum] == 1||sum==0||nums[i]==0) {ans++;mp.clear();sum = 0;continue;}mp[sum] = 1;}cout << ans << endl;
}
signed main() {int t; cin >> t;while (t--)solve();return 0;
}