传送门:http://codeforces.com/contest/899
899A - Splitting in Teams
题意:给你2*1e5的数,问最多能凑多少个3.(只有1和2)
思路:统计1和2的个数。先算2能匹配多少1.如果2的个数大于等于1的个数,那最大就是2的个数;如果2的个数小于1的个数,那最大的就是cnt2 + (cnt1 - cnt2) /3;
#include<bits/stdc++.h>
using namespace std;
int main ()
{
//yyy_3y
//freopen("1.in","r",stdin);
int n; cin >> n;
int cnt1 = 0;
int cnt2= 0;
for (int i = 1; i <= n; i++) {
int a; cin >> a;
if (a == 1) cnt1++;
else cnt2++;
}
int ans = 0;
if (cnt2 >= cnt1){
ans = cnt1;
}
else {
ans = cnt2 + (cnt1 - cnt2) /3;
}
cout <<ans <<endl;
}
899B - Months and Years
题意:给你一个小于的24的n,问你是否存以下n个数的连续的月份天数。
思路:赛后和别人交流了下,都选择了存3年,然后中间是闰年,这样就能包含所有的情况。直接暴力搜一遍就行。
我的话是选择记录29的个数,如果29的个数大于1肯定就是NO,然后把29变成28.
存3年搜一次。
#include<bits/stdc++.h>
using namespace std;
int a[100]= {0,31,28,31,30,31,30,31,31,30,31,30,31,31,28,31,30,31,30,31,31,30,31,30,31,31,28,31,30,31,30,31,31,30,31,30,31,31,28,31,30,31,30,31,31,30,31,30,31};
int b[25];
int main ()
{
//yyy_3y
//freopen("1.in","r",stdin);
int n; cin >> n;
int flag_2 = 0;
for (int i = 1; i <= n; i++){
cin >> b[i];
if (b[i] == 29) flag_2 ++;
if (b[i] == 29) b[i]--;
}
bool flag = 0;
for (int i = 1; i <= 24; i++){
int j;
int ii = i;
for (j = 1; j <= n; j++){
if ( a[ii++] != b[j]) break;
}
if (j == n + 1) {flag = 1; break;}
}
if (flag && flag_2 <= 1) cout << "YES" << endl;
else cout << "NO" << endl;
}
899C - Dividing the numbers
题意:将集合{1,2,…,n}划分成两个集合,使得两个集合的元素之和的绝对差值最小。
思路:因为n才6e4,我做的很暴力,就求个和,(如果数偶数那差值肯定是0,如果是奇数,那肯定是1),求和之后我就从最后一个开始减,剪到小于自身就行。
标解的话应该分四类情况,分析,算一道数学题把。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100000];
int main ()
{
//yyy_3y
//freopen("1.in","r",stdin);
ll t; cin >> t;
ll ans = (1 + t)*t/2;
if (ans & 1) cout << 1 <<endl;
else cout << 0 <<endl;
if ( t == 2){
cout << 1 << " " << 1 <<endl;
return 0;
}
ans = ans /2;
int cnt = 0;
while (1){
a[cnt++] = t;
ans = ans - t;
t--;
if (ans <= t){
if (ans == 0) break;
a[cnt++] = ans;
break;
}
}
cout << cnt;
for (int i = 0; i < cnt; i++){
cout << " " << a[i] ;
}
cout << endl;
}
899D - Shovel Sale
题意:给你一个1e9的n,1–n,你可以使任意两个数字相加,输出使最后连续为9的位数最长的情况数量。
思路:很显然是一道规律题。
1-4 没有 9。
5-49:最后一位为9
500-4999:最后两位为9
…………
也就是说 5,50,500 …………是分界线。
进行构造和枚举。
1.对于一个五位数如 abcde我们考虑最高位,如果 a
≥
5,那么构造 A= x99999(即五个9),否则 A=x9999(四个9)
枚举 x = 0->8 .
分三类情况。
第一种: n
≥
A ,对答案的贡献度为 A/2;
第二种: n
≥
(A+1)/2 ,对答案的贡献度为0;
剩下的情况 对答案的贡献度为(2*n-A+1)/2
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main ()
{
int n; cin >> n;
if (n < 5) cout << n*(n-1)/2 << endl;
else {
ll num = 5; int k;
for (int i = 1; i <= 10; i++){
if (num > n){
k = i;
break;
}
num *= 10;
}
ll temp = 0; int cnt = 0;
for (int i = 1;i <= k -1; i++){
temp = temp*10 + 9;
cnt++;
}
ll ans = 0;
for (int i = 0; i <= 8; i++){
ll A = temp + pow(10,cnt) * i;
if (A <= n) ans += A/2;
else if (n < (A+1)/2) break;
else ans += (2*n-A+1)/2;
}
cout << ans <<endl;
}
}
899E - Segments Removal
题意:给定长度为N(200000),每次将序列中长度最大部分相等的区间删去(若有多种情况删去最左端的区间),问多少次操作可以将删完。
题解: 数据结构(。・・)ノ。 优先队列维护一下。
学习到了新的姿势,很开心(●ˇ∀ˇ●)。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
priority_queue< pair <int,int> > q1,del;
int pre[maxn], nxt[maxn], num[maxn], col[maxn];
int cnt = 0;
int ans = 0;
int main ()
{
int n; scanf("%d",&n);
for (int i = 1; i <= n; i++){
int x; scanf("%d",&x);
if (x == col[cnt]) num[cnt]++;
else col[++cnt] = x, num[cnt] = 1;
}
for (int i = 1; i <= cnt; i++){
pre[i] = i-1;
nxt[i] = i+1;
q1.push(make_pair(num[i],-i));
}
while (cnt){
while (!del.empty() && del.top() == q1.top()) q1.pop(), del.pop();
int tt = -q1.top().second; q1.pop();
int t1 = pre[tt];
int t2 = nxt[tt];
nxt[t1] = t2;
pre[t2] = t1;
if (t1 && col[t1] == col[t2]){ //合并
del.push(make_pair(num[t2],-t2));
del.push(make_pair(num[t1],-t1));
num[t1] += num[t2];
nxt[t1] = nxt[t2];
pre[nxt[t2]] = t1;
q1.push(make_pair(num[t1],-t1));
cnt--;
}
cnt--,ans++;
}
printf("%d\n",ans);
return 0;
}
/*
12
22 22 22 1 333 333 333 333 1 22 22 22
*/