cf 1556(div1+div2)
比赛连接:
半天才做出B,更半天才做出C——因为少考虑了一种情况,C还WA了两次,最后才过的……
A
分析:
相当于两边同时\(+x\),然后一边\(+k\)、一边\(-k\)。稍微判断一下就好了。
代码如下
#include
using namespace std;
int T,c,d;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&c,&d);
if((c+d)&1){puts("-1"); continue;}
int x=(c+d)/2,ans=0;
if(x)ans++;
if(c==x&&d==x){printf("%d\n",ans); continue;}
if(x-c==d-x)ans++; else ans+=2;
printf("%d\n",ans);
}
return 0;
}
B
分析:
首先,最终状态一种是奇数位置是奇数、偶数位置是偶数;一种是奇数位置是偶数、偶数位置是奇数。用这个判断一下不合法情况就行了。然后两种取优。
至于怎么挪……一开始想了半天\(set\)、链表之类,为了维护挪了以后的序列。但是后来发现不用,因为每个数最终在的位置是确定的,比如奇数就是按它们的相对顺序排列在奇数/偶数位置上(保持相对顺序使操作次数最少)。所以按顺序直接朝目标位置挪就行。
那么怎么考虑奇数和偶数挪的时候彼此的影响呢?实际上只考虑把奇数挪到合适位置上就行,挪完以后会发现偶数也自然在合适位置上了。
我们从前往后按顺序挪,那会不会出现前面的一个奇数要挪到后面去,挪的过程中把后面的那个奇数挪前了,导致答案算错而且不优?实际上也不会。因为这种可以看作是先挪了后面的、再挪前面的(因为它们都要挪到后面去,所以这样更优)。
代码如下
#include
#define ll long long
using namespace std;
int const N=1e5+5;
ll const inf=1e12;
int T,n,a[N];
int ab(int x){return x<0?-x:x;}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n); int num0=0,num1=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]); a[i]%=2;
if(!a[i])num0++; else num1++;
}
if(n&1)
{
if(ab(num0-num1)!=1){puts("-1"); continue;}
ll ans=0;
if(num0>num1)
{
for(int i=1,p0=1,p1=2;i<=n;i++)
{
if(!a[i])ans+=ab(i-p0),p0+=2;
// else ans+=(i-p1),p1+=2;
}
}
else
{
for(int i=1,p1=1,p0=2;i<=n;i++)
{
if(!a[i])ans+=ab(i-p0),p0+=2;
// else ans+=(i-p1),p1+=2;
}
}
printf("%lld\n",ans);
}
else
{
if(num0!=num1){puts("-1"); continue;}
ll a1=0,a2=0;
for(int i=1,p0=1,p1=2;i<=n;i++)
{
if(!a[i])a1+=ab(i-p0),p0+=2;
// else a1+=(i-p1),p1+=2;
}
for(int i=1,p1=1,p0=2;i<=n;i++)
{
if(!a[i])a2+=ab(i-p0),p0+=2;
// else a2+=(i-p1),p1+=2;
}
printf("%lld\n",min(a1,a2));
}
}
return 0;
}
C
分析:
这个也想了好久……我们两个两个枚举,也就是当前\(c_i\)是一群左括号,\(c_{i+1}\)是一群右括号。然后我们用一个栈记录两个值:\(rem[i]\)和\(pre[i]\),分别表示前面剩下的左括号,以及那个左括号后面跟了多少个合法的最小括号序列。下面我们考虑每个合法子串的右端点。
若\(c_i>c_{i+1}\),说明当前左括号多于右括号,那么\(ans += c_{i+1}\),而\(c_{i+1}\)这些右括号作为右端点也再不能往前走了。栈增加一个元素,\(res[i] = c_i - c_{i+1}, pre[i]=1\)。
若\(c_i<c_{i+1}\),说明当前右括号多于左括号,那么首先$ans += c_i, c_{i+1} -= c_i \(,然后右括号继续往前走,也就是提取栈里的元素,每次\)ans += pre[i], ans += rem[i], c_{i+1} -= rem[i]\(,直到栈空了或者\)c_{i+1} \leq rem[i]\(。
如果是\)c_{i+1} < rem[i]\(,说明右括号在这里用完了,那么\)ans += c_{i+1}, rem[i] -= c_{i+1}\(,然后\)pre[i]=1\(,表示当前最右的括号与栈内此元素的左括号形成了一个合法子串。
如果是\)c_{i+1} = rem[i]\(,那么左右括号在这里恰好匹配完了。对应操作一番即可。这里要注意!!匹配完以后\)ans\(还要加上栈内前一个元素的\)pre\(,表示匹配后的子串还可以连上那些合法子串计入答案!!一开始写的时候没注意这个,调了一小时。
若\)c_i=c_{i+1}\(,和上面类似。
因为每个位置至多入栈出栈一次,所以时间复杂度是\)O(n)$的。
代码如下
#include
#define ll long long
using namespace std;
int const N=1005;
int n,c[N],cnt;
ll ans,rem[N],pre[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&c[i]);
for(int i=1;i<=n;i+=2)
{
if(i==n)continue;//!
if(c[i]>c[i+1])
{
ans+=c[i+1];
rem[++cnt]=c[i]-c[i+1]; pre[cnt]=1;
}
else if(c[i]==c[i+1])
{
ans+=c[i];
if(cnt)ans+=pre[cnt],pre[cnt]++;//rem[cnt]=0 only at head
else rem[++cnt]=0,pre[cnt]=1;
}
else
{
ans+=c[i]; int rt=c[i+1]-c[i];
while(cnt&&rt>rem[cnt])//rt!=0
{
ans+=pre[cnt]; ans+=rem[cnt];
rt-=rem[cnt]; cnt--;
}
if(cnt)
{
/*
if(rt==0)//! rt=0&&rem=0
{
ans+=pre[cnt]; pre[cnt]++;
continue;
}
*/
if(rt==rem[cnt])
{
ans+=pre[cnt]; ans+=rem[cnt];
cnt--;
if(cnt)
{
ans+=pre[cnt];//!!
pre[cnt]++;
}
else rem[++cnt]=0,pre[cnt]=1;
}
else
{
ans+=pre[cnt]; ans+=rt;
rem[cnt]-=rt; pre[cnt]=1;
}
}
}
// printf("i=%d ans=%lld\n",i,ans);
}
printf("%lld\n",ans);
return 0;
}
D
分析:
又忘记了那个重要的式子:\((x or y) + (x and y) = (x+y)\)
所以可以问六次得到前三个数的值;知道一个数的值以后就可以\(2n\)次询问把后面\(n\)个数都得到。然后排序即可。
如此简单粗暴……
代码如下
#include
#include
#define ll long long
using namespace std;
int const N=1e4+5;
int n,k,a[N];
int main()
{
scanf("%d%d",&n,&k);
ll s1,s2,s3,sum,x,y;
puts("or 1 2"); fflush(stdout);
scanf("%lld",&x);
puts("and 1 2"); fflush(stdout);
scanf("%lld",&y);
s1=x+y;
puts("or 2 3"); fflush(stdout);
scanf("%lld",&x);
puts("and 2 3"); fflush(stdout);
scanf("%lld",&y);
s2=x+y;
puts("or 1 3"); fflush(stdout);
scanf("%lld",&x);
puts("and 1 3"); fflush(stdout);
scanf("%lld",&y);
s3=x+y;
sum=(s1+s2+s3)/2;
a[1]=sum-s2; a[2]=sum-s3; a[3]=sum-s1;
for(int i=4;i<=n;i++)
{
printf("or 1 %d\n",i); fflush(stdout);
scanf("%lld",&x);
printf("and 1 %d\n",i); fflush(stdout);
scanf("%lld",&y);
a[i]=x+y-a[1];
}
sort(a+1,a+n+1);
printf("finish %d\n",a[k]);
return 0;
}
原文地址:https://www.cnblogs.com/Zinn/p/15205098.html
- 手把手在亚马逊EC2上搭建Keras GPU
- 移动商城第三篇(商品管理)【查询商品、添加商品】
- 移动商城第四篇(商品管理)【添加商品续篇、商品审核和上下架、前台展示、后台筛选】
- 移动商城第五篇(用户模块)【用户登陆、回显用户、拦截器、收货地址】
- 移动商城第六篇【单品查询、静态化页面】
- 移动商城第七篇【购物车增删改查、提交订单】
- Shiro入门这篇就够了【Shiro的基础知识、回顾URL拦截】
- OFTest(一):如何忽略一些字段在端口poll报文
- Shiro第二篇【授权、整合Spirng、过滤器】
- Ajax数据的爬取(淘女郎为例)
- 在IDEA中编写Spark的WordCount程序
- Shiro第三篇【授权过滤器、与ehcache整合、验证码、记住我】
- Spark核心RDD、什么是RDD、RDD的属性、创建RDD、RDD的依赖以及缓存、
- Caused by: java.net.ConnectException: Connection refused: master/192.168.3.129:7077
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【50期】基础考察:ClassNotFoundException 和 NoClassDefFoundError 有什么区别
- MySQL 8.0新特性 — 管理端口
- 从单词嵌入到文档距离 :WMD一种有效的文档分类方法
- 程序员技术选型:写Go还是Java?
- 用python爬虫简单网站却有 “多重思路”--猫眼电影
- 对开发者而言,GitHub Profile可能是比简历更好的求职利器
- R语言中GLM(广义线性模型),非线性和异方差可视化分析
- leetcode树之二叉树的深度
- PowerBI DAX 库存余量模型与计算
- 20种小技巧,玩转Google Colab
- 图深度学习入门教程(九)——图滤波神经网络模型
- 技术分享 | 我的内存去哪儿?生产实践
- 数据传输 | DTLE 3.20.09.0 来啦!
- R语言对巨灾风险下的再保险合同定价研究案例:广义线性模型和帕累托分布Pareto distributions分析
- 精解四大集合框架:Set核心知识总结