前言:质量超级高的div.2

B:

题意:

给你\(n\)个数,问是否可以在其中选出4个使得构成一个等腰梯形,如果可以就输出方案,否则输出\(-1\)

思路:

考虑可以构成等腰梯形的充要条件:设此等腰梯形的两个腰长度为\(c\),两个底为\(a,b\),则\(|a-b| < 2c\)

若存在至少两对相同的边长,则其一定能构成等腰梯形

若只有一对,则根据充要条件判断

否则无解

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set> const int N = 2e5 + 10;
int a[N]; void solve(){
int n;
std::cin >> n;
for(int i = 1;i <= n;++i){
std::cin >> a[i];
}
std::sort(a + 1,a + n + 1);
for(int i = n;i >= 4;--i){
if(a[i] == a[i - 3]){
std::cout << a[i] << ' ' << a[i] << ' ' << a[i] << ' ' << a[i] << '\n';
return;
}
}
std::set<int> s;
for(int i = n;i >= 2;--i){
if(a[i] == a[i - 1]) s.insert(a[i]);
} if(s.empty()) {
std::cout << -1 << '\n';
return;
}
if((int)s.size() >= 2){
auto it = s.begin();
int x = *it;
++it;
int y = *it;
std::cout << x << ' ' << x << ' ' << y << ' ' << y << '\n';
return;
} int x = *s.begin();
int p = (int)(std::lower_bound(a + 1,a + n + 1,x) - a);
for(int i = p;i <= n - 2;++i){
a[i] = a[i + 2];
}
n -= 2;
for(int i = 2;i <= n;++i){
if(a[i] - a[i - 1] < 2 * x){
std::cout << a[i - 1] << ' ' << x << ' ' << x << ' ' << a[i] << '\n';
return;
}
} std::cout << -1 << '\n';
} int main(){
int T;
std::cin >> T;
while(T--) solve();
return 0;
}

C:(小清新动态规划题)

题意:题面

转化题意:

找到一组 诚实 / 说谎 的分配, 使得没有两个说谎者可以站在一起, 并且满足所有诚实的人说的都是真的

思路:

考虑令\(f_{i,0/1}\)表示考虑到\(i\)人, 其中这个人是诚实还是说谎,考虑转移, 可以确定的是不能记录当前有多少个说谎者, 考虑找性质使其可以直接解决

重要性质:

若当前人说谎,则其左边的人一定是诚实的

那么考虑当前是诚实的人

1.\(a_{i} = a_{i-1}\)

那么若左边的人是诚实的,则满足题意;若左边的人是说谎的,那么由题意,左边的左边那个人一定是诚实的,所以若\(a_{i-2} + 1 = a_{i}\) 这种情况才可以成立

2.\(a_{i}\neq a_{i-1}\)

那么若左边的人是诚实的,则一定不满足题意;若左边的人是说谎的,那么由题意,左边的左边那个人一定是诚实的,所以若\(a_{i - 2} + 1 = a_{i}\)这种情况才可以成立

由上述条件,\(f\)的转移就十分简单了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int MAXN = 2e5 + 20;
const int MOD = 998244353; namespace calc {
int add(int a, int b) { return a + b > MOD ? a + b - MOD : a + b; }
void addon(int &a, int b) { a = add(a, b); }
} using namespace calc; int n;
int a[MAXN]; int dp[MAXN][2]; void solve(){
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]); memset(dp, 0, sizeof dp);
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
addon(dp[i][1], dp[i - 1][0]);
if (a[i] == a[i - 1]) {
if (a[i - 2] + 1 == a[i]) addon(dp[i][0], dp[i - 1][1]);
addon(dp[i][0], dp[i - 1][0]);
} else {
if (a[i - 2] + 1 == a[i]) addon(dp[i][0], dp[i - 1][1]);
}
} printf("%d\n", add(dp[n][0], dp[n][1]));
} int main()
{
int T;
scanf("%d", &T);
while (T--) solve();
return 0;
}

D:(逆向思维好题)

题意:题面

思路:

我们发现,如果真的按题意模拟合并数组\(a\),处理起来非常复杂,正难则反,若我们考虑将\(b\)数组中的元素拆分之后与\(a\)再比较会舒服很多,因为对于一个数\(x\),若要满足题意限制,则一定只能拆分成\(\lfloor\frac{x}{2}\rfloor\)与\(\lceil\frac{x}{2}\rceil\)这样的形式

我们可以对\(b\)中的数字进行这种拆分操作,正好\(n-m\)次。如果\(b\)中的最大数字也出现在\(a\)中,我们可以同时将其从\(a\)和\(b\)中删除。否则,\(b\)中最大的数字必须拆分为两个较小的数字

为了有效地管理\(a\)和\(b\)中的数字,我们可以使用优先队列或多重集。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<set>
#include<vector>
#define int long long
const int N = 2e5 + 10; int a[N],b[N];
void solve(){
int n,m,sa = 0,sb = 0;
std::cin >> n >> m;
for(int i = 1;i <= n;++i) {
std::cin >> a[i];
sa += a[i];
}
for(int i = 1;i <= m;++i) {
std::cin >> b[i];
sb += b[i];
}
if(sa != sb){
std::cout << "No" << '\n';
return;
} std::multiset<int> s;
for(int i = 1;i <= n;++i) s.insert(a[i]);
for(int i = 1;i <= m;++i){
std::vector<int> stk;
stk.push_back(b[i]);
while(!stk.empty()){
int y = stk.back();
stk.pop_back();
if(s.find(y) != s.end()){
s.erase(s.find(y));
}else{
if(y == 1){
std::cout << "No" << '\n';
return;
}
stk.push_back(y / 2);
stk.push_back(y - y / 2);
}
}
}
std::cout << "Yes" << '\n';
} signed main(){
int T;
std::cin >> T;
while(T--) solve();
return 0;
}

E:(数学好题)

题意:题面

思路:

这道题其实如果严谨做出来并且在考场上A掉,那么其一定具有较高的数学素养,但是很可惜,大部分人都是赌王,直接在考场上赌出贪心思路,甚至有人根本没发现自己算法的不严谨性

因为最终答案是让你求出\(min\{\sum a_{i}\}\)所以我们希望可以每次都使\(a_{i}\)尽可能减去更多的值,有人问了,你怎么确定每次\(a_{i}\)一定不会增加呢?这其实就涉及到了按位与运算的性质,很好证明

那么好,我们令\(g_{i,j}\)表示对于\(a_{i}\)我们执行\(j\)次操作后,\(a_{i}\)的最小值,所以显然的,因为\(m\)的范围很小,我们可以直接状态压缩集合来暴力预处理。

现在,我们给出一个非常重要的结论(很多人考场根本没有发现自己这一部分漏洞):

首先为了方便,对于每一个\(a_{i}\)其代价函数\(g\)我们直接表示为\(g_{i}(1 < i \le m)\)

那么一定有:

\[2g_{i} < g_{i-1} + g_{i+1}
\]

也就是函数\(g\)呈凸性

proof(太妙了):

令\(S\)为产生\(g_{i-1}\)的操作集合(\(|S|=i-1\)),\(T\)为产生\(g_{i+1}\)的操作集合(\(|T|=i+1\)),令\(g_{i - 1}\)与\(g_{i + 1}\)的最高不同位为\(w\),则由按位与操作的性质,一定有\(g_{i-1}\)这一位是\(1\),而\(g_{i+1}\)是\(0\),(有用且有趣的性质,想一想为什么)。

令函数\(f(S)\)表示对于这一个\(a_{i},(|S| = i)\),操作集合\(S\)产生的值,所以形式化的,我们可以给出下列式子:

\[g_{i}=min_{|S|=i}\{f(S)\}
\]

所以显然注意到:

\[\forall_{S,|S|=i}\ f(S) \ge g_{i}
\]

有了这些铺垫,我们又注意到一定\(\exists_{y\in T-S}\)(这里的\(T-S\)表示集合的差)使得\(g_{i - 1}\)的第\(w\)位变成\(0\),且\(|S\bigcup \{y\}|=i\)。

所以一定有:

\[g_{i-1}-f(S\bigcup \{y\}) \ge 2^w
\]

又因为此时\(f(S\bigcup \{y\})\)与\(g_{i+1}\)最多只在第\((w-1)\)位不同所以又有:

\[f(S\bigcup \{y\})-g_{i+1}\le 2^w - 1
\]

联立上述两个不等式我们可以得到以下放缩:

\[2g_{i}\le2f(S\bigcup \{y\})<g_{i-1}+g_{i+1}
\]

即:

\[2g_{i} < g_{i-1} + g_{i+1}
\]

Q.E.D

那么现在我们就可以继续流畅地解决这道题了我们发现对于数组\(g_{i}\)可以做差分操作,即:\(g_{i,j}=g_{i,j}-g_{i,j-1}\)又因为\(g\)刚刚证明过的凸性,可以得出对于每一个\(i\),\(g_{i}\)的差分序列是单调递减的,所以我们才能放心的把所有的\(g\)的差分序列放在一堆,然后按倒序排序,用\(\sum a_{i}\)减去前\(k\)个最小的即可。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#define int long long
#define count_1 __builtin_popcount
using namespace std; const int N = 1e5;
const int M = 15;
const int INF = 0x3f3f3f3f3f3f3f;
int a[N],b[M],val[N * 10 + 5],f[1 << 10],pre[N]; bool cmp(int a,int b){
return a > b;
} void solve(){
int n,m,mx;
std::cin >> n >> m >> mx;
for(int i = 1;i <= n;++i) std::cin >> a[i];
for(int i = 1;i <= m;++i) std::cin >> b[i];
for(int i = 1;i <= n * m;++i) val[i] = 2e9; for(int S = 1;S < (1 << m);++S){
pre[S] = (1ll << 31) - 1;
for(int i = 1;i <= m;++i)if((S >> i - 1 ) & 1) pre[S] &= b[i];
} for(int i = 1;i <= n;++i){
f[0] = a[i];
for(int S = 1;S < (1 << m);++S){
f[S] = a[i] & pre[S];
int pos = (i - 1) * m + count_1(S);
val[pos] = min(val[pos],f[S]);
}
for(int j = i * m;j > (i - 1) * m + 1;--j) val[j] = val[j - 1] - val[j];
val[(i - 1) * m + 1] = a[i] - val[(i - 1) * m + 1];
}
int tot = n * m;
std::sort(val + 1,val + 1 + tot,cmp);
int ans = 0;
for(int i = 1;i <= n;++i) ans += a[i];
for(int i = 1;i <= mx;++i) ans -= val[i];
std::cout << ans << '\n';
} signed main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr), std::cout.tie(nullptr);
int T;
std::cin >> T;
while(T--) solve();
return 0;
}

F1:

这个没什么特别惊艳的,直接给代码吧。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
const int N = 4e5 + 10;
int n,m1,m2,lens[N],lent[N]; void solve(){
std::string s,t;
std::cin >> s >> t;
n = s.length();
char u = t[0],v = t[n - 1];
s = u + s + v,t = u + t + v,n += 2;
int tmp_len = 0;
m1 = m2 = 0;
for(int i = 0;i < n;++i){
if(i > 0 && s[i] != s[i - 1]) lens[++m1] = tmp_len,tmp_len = 1;
else ++tmp_len;
}
lens[++m1] = tmp_len;
tmp_len = 0;
for(int i = 0;i < n;++i){
if(i > 0 && t[i] != t[i - 1]) lent[++m2] = tmp_len,tmp_len = 1;
else ++tmp_len;
}
lent[++m2] = tmp_len;
int i = 1,j = 1;
while(j <= m2){
if(i > m1) {
std::cout << -1 << '\n';
return;
}
if(lent[j] < lens[i]){
std::cout << -1 << '\n';
return;
}
if(lent[j] == lens[i]){++i,++j;continue;}
if(i == m1){
std::cout << -1 << '\n';
return;
}
int x = lens[i],y = lens[i + 1];
if(j + 1 <= m2){
while(i + 3 <= m1){
x += lens[i + 2],y += lens[i + 3],i += 2;
if(x > lent[j]) {
std::cout << -1 << '\n';
return;
}
if(x == lent[j]) break;
}
if(x == lent[j]) ++i,++j,lens[i] = y;
else {
std::cout << -1 << '\n';
return;
}
}else{
std::cout << -1 << '\n';
return;
}
}
if(i > m1) std::cout << (m1 - m2) / 2 << '\n';
else {
std::cout << -1 << '\n';
return;
}
} int main(){
int T;
std::cin >> T;
while(T--) solve();
return 0;
}

F2:(It's so difficult that I think I should depend on my father's power.)

题意:题面

思路:

1.21Codeforces Round 999 (part div.2)的更多相关文章

  1. VK Cup 2012 Round 3 (Unofficial Div. 2 Edition)

    VK Cup 2012 Round 3 (Unofficial Div. 2 Edition) 代码 VK Cup 2012 Round 3 (Unofficial Div. 2 Edition) A ...

  2. Codeforces 1023 A.Single Wildcard Pattern Matching-匹配字符 (Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Fi)

    Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final) A. Single Wildcard Patter ...

  3. Codeforces Round #405 (rated, Div. 2, based on VK Cup 2017 Round 1) 菜鸡只会ABC!

    Codeforces Round #405 (rated, Div. 2, based on VK Cup 2017 Round 1) 全场题解 菜鸡只会A+B+C,呈上题解: A. Bear and ...

  4. Codeforces Round #581(Div. 2)

    Codeforces Round #581(Div. 2) CF 1204 A. BowWow and the Timetable 题解:发现,$4$的幂次的二进制就是一个$1$后面跟偶数个$0$. ...

  5. Codeforces Round #412 (rated, Div. 2, base on VK Cup 2017 Round 3)(A.B.C,3道暴力题,C可二分求解)

    A. Is it rated? time limit per test:2 seconds memory limit per test:256 megabytes input:standard inp ...

  6. 【Codeforces Round】 #432 (Div. 2) 题解

    Codeforces Round #432 (Div. 2, based on IndiaHacks Final Round 2017)  A. Arpa and a research in Mexi ...

  7. 【Codeforces Round】 #431 (Div. 2) 题解

    Codeforces Round #431 (Div. 2)  A. Odds and Ends time limit per test 1 second memory limit per test ...

  8. Codeforces Round #412 (rated, Div. 2, base on VK Cup 2017 Round 3) A B C D 水 模拟 二分 贪心

    A. Is it rated? time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  9. Codeforces Round #370 - #379 (Div. 2)

    题意: 思路: Codeforces Round #370(Solved: 4 out of 5) A - Memory and Crow 题意:有一个序列,然后对每一个进行ai = bi - bi  ...

  10. Codeforces Round #412 (rated, Div. 2, base on VK Cup 2017 Round 3) D - Dynamic Problem Scoring

    地址:http://codeforces.com/contest/807/problem/D 题目: D. Dynamic Problem Scoring time limit per test 2 ...

随机推荐

  1. Java并发基础之多线程

    文章也发布在我的个人博客上:https://blog.ysboke.cn/archives/129.html 概述 每个Thread类的示例都代表一个线程,而进程是操作系统级别的多任务,JVM就是运行 ...

  2. Windows平台调试器原理与编写05.内存断点

    https://www.bpsend.net/thread-274-1-3.html 内存断点 访问断点 写入断点 内存写入断点 简介:当被调试进程访问,读或写指定内存的时候,程序能够断下来. 思考1 ...

  3. 代码随想录第十天 | 栈与队列part02

      第五章 栈与队列part02 150. 逆波兰表达式求值 本题不难,但第一次做的话,会很难想到,所以先看视频,了解思路再去做题 题目链接/文章讲解/视频讲解:https://programmerc ...

  4. Hive对JSON格式的支持研究

    一.背景 JSON是一种通用的存储格式,在半结构化存储中十分常见,部分场景已经开始存在以JSON格式贴源存储的数据,作为下游数据使用方,我们亟需对JSON格式的数据进行加工和处理,以提取出我们需要的数 ...

  5. 「Log」NOIP 2023 游记

    Day 0 打了大半天板子,然后开摆. 打块,快下班的时候玩了猜词游戏. 回家睡大觉. Day 1 早上起床状态良好,收拾收拾就出门了,跟爸妈吃了肯德基,然后坐车到三校区. 才看到 cc0000 之前 ...

  6. 「Log」2023.8.28 小记

    序幕 七点多到校,整理博客,开了一篇新做题记录. 整理一下学过知识点,准备阶段复习. 八点整开始打模拟赛,接下来算游记. T1 是个静态区间第 \(k\) 小板子,纯主席树被空间卡掉了,打了 \(60 ...

  7. 【中文】【吴恩达课后编程作业】Course 1 - 神经网络和深度学习 - 第二周作业

    [吴恩达课后编程作业]Course 1 - 神经网络和深度学习 - 第二周作业 - 具有神经网络思维的Logistic回归 上一篇:[课程1 - 第二周测验]※※※※※ [回到目录]※※※※※下一篇: ...

  8. Jenkins概述及Linux系统中安装

    概述 官网:https://www.jenkins.io/ GitHub地址:https://github.com/jenkinsci/jenkins Jenkins是一个用Java编写的开源的持续集 ...

  9. Lecture2 Linear methods for regression, Optimization

    书接上回,KNN模型有两个好处,一个是它很简单,另一个就是它既可以用来做回归,又可以用来做分类.但是坏处也很明显,就是它太粗暴了,基本上不怎么学习,只是对数据做一个简单的存储,等有了新的数据(测试数据 ...

  10. 苹果Apple验证码无法发送至该电话号码。请稍后重试

    前言 因为CSDN的种种作为,广告,非同意文章收费等原因,此后我的文章将转移博客园发布登陆苹果账户,输入账户登陆不发送验证码,旧手机号不用,重置了新手机号,新密码,登陆不上系统 解决1拨打苹果客服电话 ...