Codeforces Round #690 (Div. 3)解题报告
作者:互联网
题目链接:https://codeforces.com/contest/1462
以后要坚持补题写题解呀~
A:Favorite Sequence
题目大意
给一个序列,按照序列首尾首尾的取元素
思路
vector简单模拟
AC代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int a[305];
int main(){
int t; cin >> t;
while(t --){
int n; cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
vector<int> v;
int l = 1, r = n;
while(l < r){
v.push_back(a[l]);
v.push_back(a[r]);
l ++; r --;
}
if(n & 1) v.push_back(a[l]); //如果n为奇数,则会多出一个值
for(int i = 0; i < v.size(); i ++){
if(i) cout << " ";
cout << v[i];
}
cout << endl;
}
return 0;
}
B:Last Year's Substring
题目大意
给一个字符串,问能否最多删除连续一段使得剩下的字符串是“2020”?
思路
因为最多删除一段,中间两边分别判断一下就好了
AC代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
char a[305];
int main(){
int t; scanf("%d",&t);
while(t --){
int n; scanf("%d%s",&n, a + 1);
if(a[1] == '2' && a[2] == '0' && a[3] == '2' && a[4] == '0') puts("YES"); //从5开始删
else if(a[1] == '2' & a[2] == '0' && a[3] == '2' && a[n] == '0') puts("YES"); //从4开始删
else if(a[1] == '2' && a[2] == '0' && a[n - 1] == '2' && a[n] == '0')puts("YES");//从3开始删
else if(a[1] == '2' && a[n - 2] == '0' && a[n - 1] == '2' && a[n] == '0') puts("YES");//从2开始删
else if(a[n - 3] == '2' && a[n - 2] == '0' && a[n - 1] == '2' && a[n] == '0') puts("YES");//从1开始删
else puts("NO");
}
return 0;
}
C:Unique Number
题目大意
输出最小的数位和等于x并且各个数位都不一样的值
思路
低位的数位越大越好,最后一位从9开始枚举,倒数第二位从8开始枚举,以此类推。。。减到n不够减,当n>45是,出 -1
AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
int main(){
int t; scanf("%d",&t);
while(t --){
int n; scanf("%d",&n);
if(n > 45) {
puts("-1");
continue;
}
int d = 9;
string a;
char ch;
while(n){
if(n <= d){
ch = n + '0';
a = ch + a;
n = 0;
} else{
n -= d;
ch = d + '0';
d --;
a = ch + a;
}
}
cout << a << endl;
}
return 0;
}
D:Add to Neighbour and Remove
题目大意
给出一个序列,相邻的可以左右合并,问最后最多可以分成多少段相同的值。
思路
总和是sum,枚举分成的份数(当然就是sum的因子啦),然后更新最小值
AC代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int a[3005], n;
ll cal(ll x){
ll ans = 0, res = 0;
int i = 1;
while(i <= n){
res += a[i ++];
if(res == x){
res = 0;
continue;
}
if(res > x) return n - 1; // 分不了的话只能合并成一个了
ans ++;
}
return ans;
}
int main(){
int t; scanf("%d",&t);
while(t --){
scanf("%d",&n);
ll sum = 0;
for(int i = 1; i <= n; i ++){
scanf("%d",&a[i]);
sum += a[i];
}
ll ans = n - 1;
for(ll i = 1; i * i <= sum; i ++){
if(sum % i == 0){ //可以分成i份和sum/i份
ll a1 = cal(i);
ll a2 = cal(sum / i);
ans = min(ans, min(a1, a2));
}
}
printf("%lld\n", ans);
}
return 0;
}
E1:
题目大意
给出一个序列,抽出3个数,这3个数的最大值减去最小值小于等于2,问能抽出多少组数
思路
这是简单版本,那map存个数,分类讨论。六种情况:【a,a,a】【a,a,a+1】【a,a+1,a+1】【a,a,a+2】【a,a+2,a+2】【a,a+1,a+2】
AC代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
map<int, int> mp;
int main(){
int t; scanf("%d",&t);
while(t --){
int n; scanf("%d",&n);
mp.clear();
while(n --){
int x; scanf("%d",&x);
mp[x] ++;
}
ll ans = 0;
for(auto it : mp){
int d = it.first;
int num = it.second;
if(num >= 3) ans += 1ll * num * (num - 1) * (num - 2) / 6; //a,a,a
if(mp.count(d + 1)){
int dd = mp[d + 1];
if(num >= 2) ans += 1ll * num * (num - 1) / 2 * dd;//a,a,a+1
if(dd >= 2) ans += 1ll * dd * (dd - 1) / 2 * num;//a,a+1,a+1
if(mp.count(d + 2)) {
ans += 1ll * num * mp[d + 1] * mp[d + 2];//a,a+1,a+2
}
}
if(mp.count(d + 2)){
int ddd = mp[d + 2];
if(ddd >= 2) ans += 1ll * ddd * (ddd - 1) / 2 * num;//a,a+2,a+2
if(num >= 2) ans += 1ll * num * (num - 1) / 2 * ddd;//a,a,a+2
}
}
printf("%lld\n",ans);
}
return 0;
}
E2:
题目大意
和上题一样但是m,k变成未知数,数据很大结果要取mod
思路
给的时限很多,可以双指针枚举最左边的数,然后剩下的数中取m-1个数,求个组合数
AC代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
const ll mod = 1e9 + 7;
ll fac[maxn], inv[maxn];
ll _pow(ll a, ll b){
ll ans = 1;
while(b){
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
void init(){ //预处理阶乘数和阶乘数的逆元
fac[0] = 1;
for(int i = 1; i < maxn; i ++)
fac[i] = fac[i - 1] * i % mod;
inv[maxn - 1] = _pow(fac[maxn - 1], mod - 2);
for(int i = maxn - 2; i >= 0; i --)
inv[i] = inv[i + 1] * (i + 1) % mod;
}
ll c(ll a, ll b){ //求组合数
if(a < b) return 0;
return fac[a] * inv[b] % mod * inv[a - b] % mod;
}
ll a[maxn];
int main(){
init();
int t; scanf("%d",&t);
while(t --){
int n, m, k;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i <= n; i ++) scanf("%d",&a[i]);
sort(a + 1, a + n + 1);
int l = 1;
ll ans = 0;
for(int r = m; r <= n; r ++){
while(a[r] - a[l] > k) l ++; //满足区间内跨度小于等于k
if(r - l + 1 < m) continue; //满足区间内数量大于等于m
ans = (ans + c(r - l, m - 1)) % mod;
}
printf("%lld\n", ans);
}
return 0;
}
F:The Treasure of The Segments
题目大意
给你n个二元组,代表线段的左右端点,问最少删几条线段,使得剩下当中存在一个线段与所有剩下的所有线段都有交集。
思路
枚举每一个二元组作为那个特殊线段时需要删的线段数,更新最小值。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
int a[maxn], b[maxn];
int x[maxn], y[maxn];
int main(){
int t; scanf("%d",&t);
while(t --){
int n; scanf("%d",&n);
for(int i = 1; i <= n; i ++){
scanf("%d%d",&a[i], &b[i]);
x[i] = a[i];
y[i] = b[i];
}
sort(x + 1, x + n + 1);
sort(y + 1, y + n + 1);
int l, r, ans = n;
for(int i = 1; i <= n; i ++){
int l = (lower_bound(y + 1, y + n + 1, a[i]) - y) - 1; //右端点小于当前左端点的数量
int r = n - (upper_bound(x + 1, x + n + 1, b[i]) - x) + 1;//左端点大于当前右端点的数量
ans = min(ans, l + r);
}
printf("%d\n", ans);
}
return 0;
}
标签:690,int,ll,Codeforces,num,maxn,&&,ans,Div 来源: https://blog.csdn.net/weixin_43911947/article/details/111286293