CF Div2.
写了四个的 Div2
了,知道自己差不多在哪了,继续开始突破,看看一周能不能再突破一百。
现在大约在 \(1200\) 左右。
Codeforces Round 980 (Div. 2)
B 题
本来想的是排序之后一个一个判断是否能不能超过 \(k\),如果不能则需要比这个多一次才能跳到下一个数组上,没想到连样例都没过。
后来看了看样例解释就懂了,同样是排序,变成递增的,然后一个一个判断能不能这个数后面的每个都去和他一样的话,总和能不能超过所需要的饮料,能的话就需要多一次去判断是否是空的了。
如果不能,那这个不行,就只能用完这个了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include<bits/stdc++.h>
using namespace std; const long long maxn = 200010; long long T; long long a[maxn];
int main() { cin>>T; while(T--){ long long n,k;cin>>n>>k; for(long long i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); long long ans = 0; for(long long i=1;i<=n;i++){ long long len = (n - i + 1); if(a[i] * len >= k){ ans += k; break; } else{ ans += (a[i] + 1); k -= a[i]; } } cout<<ans<<endl; } return 0; }
|
C 题
这道题题目根本没有什么提醒让我从哪里想,题解就感觉很空穴来风,样例解释也没有什么可以往这上面靠的。
题解思路就是用这两个小数组的总和作为值从小到大排序,最后排序的结果就是答案。题解证明:注意,如果在最终的顺序中有两个相邻的数组,左边数组的元素之和大于右边数组的元素之和,那么我们可以交换它们,并且逆序对的数量不会增加。因此,我们可以通过交换相邻的数组,使得每次逆序对的数量不增加,从而将任何最优解转化为我们的解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include<bits/stdc++.h>
using namespace std;
const int maxn = 100010; struct nums{ int a1,a2; int sum; } a[maxn];
bool cmp(nums x,nums y){ return x.sum < y.sum; }
int main() { int T; cin>>T; while(T--){ int n;cin>>n; for(int i=1;i<=n;i++){ scanf("%d %d",&a[i].a1,&a[i].a2); a[i].sum = a[i].a1 + a[i].a2; } sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++){ printf("%d %d ",a[i].a1,a[i].a2); } cout<<endl; } return 0; }
|
Codeforces Round 979 (Div. 2)
C 题
这个比赛前2题没什么难度,都是 \(800\) 分左右,有点简单了,C
题很显然是构造题,想了想,能想到有第一个或最后一个是 \(1\)
的肯定能赢,但是后面怎么处理,根本想不到。还是只能看题解了。
如果中间的有两个 true
那么一定可以赢,我们可以让 Alice
最后去管理两个 true
。首先第一个放在 or
之前。如果 Bob 没有将他的运算符放在两个 true
之间,那么
Alice 将在下一步中将 or
放在两个 true
之间并获胜。
如果没有连续的 true
,每当 Alice 将 true
或相邻位置放置时,Bob 都会通过在 true
之后放置
and
来响应,这将使此子句无效为 false
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<bits/stdc++.h>
using namespace std;
bool x[200010];
int main() { int T; cin>>T; while(T--){ int n; cin>>n; string s; cin>>s; memset(x,0,sizeof(x)); for(int i=0;i<s.length();i++) if(s[i] == '1') x[i] = 1; bool win = false; if(x[0] || x[n-1]){cout<<"YES"<<endl;continue;} for(int i=1;i<n;i++){ if(x[i] && x[i-1]) win = true; } if(win) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }
|
Codeforces Round 979 (Div.
2)
B 题
这道题挺有意思,我发现最优的方案一定是先选出 \(k\) 个最大的,然后每个减去这 \(k\) 个中最小的一个数。最后将大于 \(0\)
的数再存进去。重复这几个操作。这期间可以用堆来存储数字,这样每次读取只需要
\(O(\log n)\)
读取每个数。这种贪心不太对,在评论区也有许多人用了这种方式,但是都无一例外的
Wa 了。
直到一位老哥的解释让我恍然大悟。他说可以看看这个样例。
的确,答案确实和我们想的不太一样。其实最优方案是,每次将最大 \(k\) 个元素取出,减去 \(1\) 后再放回,但是数字要大于 \(10^9\),很显然 TLE 了。
有个更简单的方法。我们最大限度的让每个客人随机去选汽车。这样最后选不够
\(x\) 辆汽车之后,就会有两种情况;
- 所有型号都将具有相同数量的剩余汽车,很显然,这种答案就是 \(\lceil \dfrac{a_1+a_2+\dotsb + a_n}{x}
\rceil\)。
- 如果还有型号不为 \(0\)
但是个数小于等于 \(x\),那么答案为
\(\max(a_1+a_2+\dotsb +a_n)\)。
这两种结合一下就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include<bits/stdc++.h>
using namespace std;
int T;
int main() { int T; cin>>T; while(T--){ int n,r; cin>>n>>r; int cnt1 = 0,ans = 0; for(int i=1;i<=n;i++){ int x;cin>>x; cnt1 += (x % 2); ans += (x/2)*2; r -= (x/2); } if(r >= cnt1) ans += cnt1; else{ int t = cnt1 - r; ans += (cnt1 - t*2); } cout<<ans<<endl; } return 0; }
|