Sweet Round 1题解
感谢各位参赛者,所有的题解如下:
T1 syx的奖励
这题明显是签到题了吧,随便猜猜结论就A掉了
先说怎么做吧,把所有的可走的数gcd起来,然后再与n求gcd
如果为1,则输出n,若不为1,则输出-1
证明如下:
∵gcd(所有可行的数,n)=1,
∴在可行的步数中必有一点y,使得gcd(x,y)<x(x!=1)
∴有x,y等价于又了gcd(x,y)
然后就数学归纳一下,就得出了结论了鸭
注意!!!
当n==1&&m==1时,就一步都不能走了
所以输出 -1
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
int x(),neg();char ch(getchar());
while(!isdigit(ch)) {
if (ch=='-') neg=-;
ch=getchar();
}
while(isdigit(ch)) {
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return x*neg;
}
int n,k;
int mp[];
int baozi,T;
signed main() {
// freopen("baozi.in","r",stdin);
// freopen("baozi.out","w",stdout);
T=read();
for (int t=;t<=T;++t) {
memset(mp,,sizeof(mp));
n=read(),k=read();
baozi=n;
for (int i=;i<=k;++i) {
int x;
x=read();
mp[x]=;
}
for (int i=;i<=n;++i) {
if (!mp[i]) {
baozi=__gcd(baozi,i);
}
}
if (baozi!=||n==&&k==) {
puts("-1");
continue;
}
printf("%lld\n",n);
}
return ;
}
T2 Ethan and sets
思路:
挺明显的Two-pointers吧qwq
这题应该还是挺简单的,模拟即可 (Two-pointers 难不到哪里去)
直接上代码(详细注释)
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
int x(),neg();char ch(getchar());
while(!isdigit(ch)) {
if (ch=='-') neg=-;
ch=getchar();
}
while(isdigit(ch)) {
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return x*neg;
}
int n,m,g,s[],cnt[],c[][],num[],p[];
bool found=;
int ansb=,anss,ansl,ansr;
signed main() {
n=read(),m=read(),g=read();
for(int i=;i<=g;i++){
int x(read());
p[x]=;//标记为喜欢
}
for(int i=;i<=n;i++){
scanf("%lld%lld",&s[i],&num[i]);
for(int j=;j<=num[i];j++)
scanf("%lld",&c[i][j]);
}
int l=,r=,sum=,sumb=;//当前区间为 [l,r) , sum = [l,r) 的魔力值之和 , sumb = [l,r) 中不喜欢的数的个数
while(l<=n) {
while(r<=n) {
bool flag=,check=;//flag: 是否有不喜欢的数 (1=NO,0=YES) , check: 是否全部包含了所有 Ethan 喜欢的数
for(int i=;i<=num[r];++i)
if(!p[c[r][i]])
flag=;
for(int i=;i<=m;i++)
if(p[i]&&!cnt[i])//喜欢但不包含的数
check=;
if(check&&!flag)break;//如果包含了所有喜欢的数 , 且 [l,r-1] 比 [l,r] " 不喜欢的数的个数 " 少 ( 集合 r 有不喜欢的数 ) , 那就选 [l,r-1] , 退出
for(int i=;i<=num[r];++i){//右端点往右移 , 加上集合 r 的所有属性
if(!p[c[r][i]]) ++sumb;
++cnt[c[r][i]];
}
sum+=s[r];
++r;//右端点 ++
}
bool check=;//这边还要再判断一下是否有全部喜欢的数 , 可能是 r>n 从上一个 whlie 循环退出来的
for(int i=;i<=m;++i)
if(p[i]&&!cnt[i])
check=;
if(check) {
found=;//标记一下找到了
if(ansb>sumb||sumb==ansb&&anss<sum)//如果满足更新条件
ansb=sumb,anss=sum,ansl=l,ansr=r-;//更新
}
for(int i=;i<=num[l];++i){//左端点往右移 , 把集合 l 的所有属性减掉 ( 可以和上面的右端点往右移对比一下 )
cnt[c[l][i]]--;
if(!p[c[l][i]])sumb--;
}
sum-=s[l];
++l;//左端点 ++
}
if(!found) puts("-1");//没找到输出 -1
else printf("%lld %lld\n",ansl,ansr);
return ;
}
T3 syx与他的邪恶序列 (easy version)
这题就属于随便做的题目了吧。。。
但是如果你用T4的方法做可能还拿不到几分(看看时间和空间限制)
直接考虑贪心
在当前的点是要删除的数(=x)的时候,考虑它离最近的点需要多少步,离最近可以删的点为2k且这个点为离它前面最近的点,而它前面删掉的点有cur个,所以每个数需要(当前位置减2k-cur)次才能到达,所以得出程序:
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int x(),neg();char ch(getchar());
while(!isdigit(ch)) {
if (ch=='-') neg=-;
ch=getchar();
}
while(isdigit(ch)) {
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return x*neg;
}
int n,k,x,cnt,cur;
int main() {
int ans=;
n=read(),k=read();
for (int i=;i<=n;++i) {
x=read();
if (x==k) {
int t=i-(<<((int)log2(i)));
if (t>cur) {
ans+=t-cur;
cur=t;
}
cnt++;
cur++;
}
}
printf("%d\n",ans+cnt);
return ;
}
T4 syx与他的邪恶序列 (hard version)
前言:
其实这题出题的时候也是我和csy在操场上聊天,然后就突然有了灵感,去出这一题(所以非常水啊!!!)
题解:
其实这个n≤3∗106我觉得提示已经很明显了,肯定要不是O(1),要不就是O(n),要不是O(nlogn),但是想想O(1)和O(n),好像又很不可做的亚子,于是就奔着O(nlogn)的方向去了吧
首先,大家可以思考一下,如果有位置在2k的数,那么一定会弹掉。但是弹哪个呢???
肯定是弹最后一个啊!因为弹前面的一定会影响后面的,会使后面的不再在2k这个位置上,所以思路是很明显的,然后看怎么实现
对于实现,可能大家第一步想到的是O(n2)的算法,就是先找有没有目标要删除的数在2k这个位置上,如果有,记录最后一个,然后把那个删掉(删掉操作可能就把数组忘前移吧),再++cnt,如果没有,就把第一个数删掉(因为当前的第一个数也是2k,所以没有的话,第一个数肯定不是目标要删除的数),然后把所有的数往前移,知道把所有的目标要删的数都搞完为止
恭喜你,获得了35分的高分!!!
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
int x(),neg();char ch(getchar());
while(!isdigit(ch)) {
if (ch=='-') neg=-;
ch=getchar();
}
while(isdigit(ch)) {
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return x*neg;
}
int pos[];
int cnt,now[],pw[],used[],ok[],a[],ans[],tot;
signed main() {
int n1=read(),k=read();
pw[]=;
used[]=;
for (int i=;i<;++i) {
pw[i]=pw[i-]*;
used[pw[i]]=;
}
for (register int i=;i<=n1;i++) {
int t=read();
if (t==k) {
register int k=;
pos[++cnt]=i;
now[cnt]=i;
}
}
int cntt=cnt;
int start=;
while(cntt) {
int flag=;
for (int i=cnt;i>=;--i) {
if (used[pos[i]]&&!ok[now[i]]) {
ans[++tot]=now[i];
cntt--;
flag=;
ok[now[i]]=;
for (int j=i+;j<=cnt;++j) --pos[j];
break;
}
}
if (flag) continue;
while(true) {
++start;
if (!ok[start]) {
ok[start]=;
break;
}
}
for (int j=cnt;j>=;--j) {
if (pos[j]<start) break;
--pos[j];
}
ans[++tot]=start;
}
printf("%lld\n",tot);
for (int i=;i<=tot;++i) {
printf("%lld ",ans[i]);
}
return ;
}
/*
5 2
2 2 2 2 2 3 3
1 1 3
*/
然后再看看复杂度
于是就发现非常不行,就开始往数据结构上想,要维护最后一个可以删的数咋办啊?
然后就考虑用线段树记录每个数离它要删除的地方的位置,如果这个线段的区间最小值为0,那么就说明可以删,就先看它的右节点为不为0,如果为0,就直接往右节点跑,如果不为0,那么就说明应该往左节点跑,找到最右边
然后就发现你已经把这题想好了,然后就花个5min写代码吧
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int x(),neg();char ch(getchar());
while(!isdigit(ch)) {
if (ch=='-') neg=-;
ch=getchar();
}
while(isdigit(ch)) {
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return x*neg;
}
struct node{
int left,right,minv,lazy;
}tree[];
int n1,k,a[],tot,noww,num[],ans2[],now[],ans;
inline void build(register int cnt,register int l,register int r) {
tree[cnt].left=l;tree[cnt].right=r;
if (l==r) {
tree[cnt].minv=a[l];
}
else {
build(cnt<<,l,l+r>>);
build(cnt<<|,(l+r>>)+,r);
tree[cnt].minv=min(tree[cnt*].minv,tree[cnt*+].minv);
}
}
inline int find(register int p) {
register int t;
if ((tree[p].minv-tree[p].lazy)!=){
register int total=tree[p].minv-tree[p].lazy;
for (register int i=;i<=total;++i) {
++noww;
while(num[noww]==k) {
++noww;
}
ans2[++tot]=noww;
}
ans+=tree[p].minv-tree[p].lazy;
tree[p].lazy=tree[p].minv;
}
if (tree[p].left==tree[p].right){
tree[p].minv=;
return tree[p].left;
}
else{
tree[p<<].lazy+=tree[p].lazy;
tree[p<<|].lazy+=tree[p].lazy;
tree[p].lazy=;
if (tree[p<<|].minv-tree[p+p+].lazy==) t=find(p*+);
else t=find(p*);
tree[p].minv=min(tree[p+p].minv-tree[p+p].lazy,tree[p+p+].minv-tree[p+p+].lazy);
return t;
}
}
inline void add(register int p,register int l,register int r) {
if (l>r) return ;
if (l<=tree[p].left&&tree[p].right<=r){
tree[p].lazy++;
}
else{
tree[p*].lazy+=tree[p].lazy;
tree[p*+].lazy+=tree[p].lazy;
tree[p].lazy=;
if (l<=(tree[p].left+tree[p].right)/) add(p*,l,r);
if ((tree[p].left+tree[p].right)/+<=r) add(p*+,l,r);
tree[p].minv=min(tree[p*].minv-tree[p*].lazy,tree[p*+].minv-tree[p*+].lazy);
}
return ;
}
int pw[];
signed main(){
// freopen("link.in","r",stdin);
// freopen("line.out","w",stdout);
n1=read(),k=read();
register int t,cnt=;
pw[]=;
for (int i=;i<;++i) {
pw[i]=pw[i-]*;
}
for (register int i=;i<=n1;i++) {
register int t;
t=read();
num[i]=t;
if (t==k) {
register int k=;
for (register int j=;j<=;++j) {
if (pw[j]>i) {
k=i-pw[j-];
break;
}
}
a[++cnt]=k;
now[cnt]=i;
}
}
if (cnt==) {
puts("");
return ;
}
build(,,cnt);
for (register int i=;i<=cnt;i++) {
t=find();
++ans;
ans2[++tot]=now[t];
add(,t+,cnt);
}
printf("%lld\n",ans);
for (register int i=;i<=tot;++i) {
printf("%lld ",ans2[i]);
}
puts("");
return ;
}
T5 Alex does homework
题解:
我也不知道这个部分分给的有什么用
Sol 1 : 5-15 pts
爆搜,期望得分 5-15% (要看你怎么搜)
Sol 2 : 75-100 pts
注意空间限制!!!
一看题就应该知道 时间 O(nk),空间 O(k)
如果没有 时间的限制,那么这道题目就是 完全背包
但有了时间怎么办 qwq?
不慌,将所有种类的作业按时间 从大到小 排序
每次一种作业去更新 dp 数组
再 对于每一个更新 求出最小(精力)花费
最后求出天数不就行了嘛 awa
最后,上代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
int x(),neg();char ch(getchar());
while(!isdigit(ch)) {
if (ch=='-') neg=-;
ch=getchar();
}
while(isdigit(ch)) {
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return x*neg;
}
const int N=;
const int INF=; struct homew{
int x,w,t,cos;
}k[N];
bool cmp(homew a,homew b){return a.t>b.t;}//将作业按时间大小排序
int x,w,n,dp[N<<]; void init() {
x=read(),w=read(),n=read();
for(int i=;i<=n;++i)
k[i].x=read(),k[i].w=read(),k[i].t=read();//读入
sort(k+,k+n+,cmp);//sort
memset(dp,0x3f,sizeof(dp));//dp 赋初值
dp[]=;
} inline void DP() {
for(int i=;i<=n;i++){
if(k[i].w>=w)//特判一下 w[i]>=w 的情况
dp[w]=min(dp[w],k[i].x);
else
for(int j=k[i].w;j<=w+k[i].w;j++)//完全背包
dp[j]=min(dp[j],dp[j-k[i].w]+k[i].x);
k[i].cos=INF;//赋初值
for(int j=w;j<=(w<<);++j)
k[i].cos=min(k[i].cos,dp[j]);//找出最小值
}
} inline void answer() {
for(int i=n;i>=;--i) {//时间从小到大遍历
int cos=k[i].cos*(k[i].t-k[i+].t);//总花费
if(cos<=x) x-=cos;//有足够的精力
else {
printf("%lld %lld",k[i+].t+x/k[i].cos,x%k[i].cos);exit();//否则输出并退出
}
}
printf("%lld %lld\n",k[].t,x);//特判天天能写完作业
}
signed main() {
// freopen("homework.in","r",stdin);
// freopen("homework.out","w",stdout);
init();
DP();
answer();
return ;
}
最后,再次感谢大家参加此次比赛!!!
Sweet Round 1题解的更多相关文章
- 「SWTR-04」Sweet Round 04 游记
比赛链接 由于 \(\texttt{Sweet Round}\) 比赛挺好的(关键不知道为啥\(Unrated\) 开篇总结(大雾):这次比赛题目不错(有思维含量) 尽管我不会做. 我一看 \(T1\ ...
- Codeforces Round #556 题解
Codeforces Round #556 题解 Div.2 A Stock Arbitraging 傻逼题 Div.2 B Tiling Challenge 傻逼题 Div.1 A Prefix S ...
- LibreOJ β Round #2 题解
LibreOJ β Round #2 题解 模拟只会猜题意 题目: 给定一个长为 \(n\) 的序列,有 \(m\) 次询问,每次问所有长度大于 \(x\) 的区间的元素和的最大值. \(1 \leq ...
- Codeforces Round #569 题解
Codeforces Round #569 题解 CF1179A Valeriy and Deque 有一个双端队列,每次取队首两个值,将较小值移动到队尾,较大值位置不变.多组询问求第\(m\)次操作 ...
- Codeforces Round #557 题解【更完了】
Codeforces Round #557 题解 掉分快乐 CF1161A Hide and Seek Alice和Bob在玩捉♂迷♂藏,有\(n\)个格子,Bob会检查\(k\)次,第\(i\)次检 ...
- CFEducational Codeforces Round 66题解报告
CFEducational Codeforces Round 66题解报告 感觉丧失了唯一一次能在CF上超过wqy的机会QAQ A 不管 B 不能直接累计乘法打\(tag\),要直接跳 C 考虑二分第 ...
- Google kickstart 2022 Round A题解
Speed Typing 题意概述 给出两个字符串I和P,问能否通过删除P中若干个字符得到I?如果能的话,需要删除字符的个数是多少? 数据规模 \[1≤|I|,|P|≤10^5 \] 双指针 设置两个 ...
- Codeforces Beta Round #62 题解【ABCD】
Codeforces Beta Round #62 A Irrational problem 题意 f(x) = x mod p1 mod p2 mod p3 mod p4 问你[a,b]中有多少个数 ...
- “玲珑杯”ACM比赛 Round #12题解&源码
我能说我比较傻么!就只能做一道签到题,没办法,我就先写下A题的题解&源码吧,日后补上剩余题的题解&源码吧! A ...
随机推荐
- 【原】Django数据Model层总结
vlaues - 单条记录 - <class 'dict'> 多条记录 - <class 'django.db.models.query.QuerySet'> vlaues_l ...
- C语言-断言
1 作用: 断言常做语言处理的高级形式,自动处理软件隐藏很深其且它手段不易发现的错误,快速进行异常定位.同时这也是软件单元测试必须的技术. 2 使用范围: 2.1放在函数入口对入口参数进行合法性检查( ...
- xml 写sql语句文件头
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-/ ...
- nyoj 82
题目:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=82 2018-06-23 23:44:05 p.s.自己省错题了: 描述 一个叫ACM的 ...
- vector 踩过的坑
今天,做LeetCode上的一道题,198题:Rob House,在纸上画了画,发现了重复的结构,就使用了递归的方式实现的 #include<iostream> #include<v ...
- FastStone Capture 截图工具
主要功能介绍 截屏 包括了全屏截取,当前活动窗口截取,截取选定区域,多边形截取和截取滚动页面等,基本上常用的都有了.特别是滚动截取,许多朋友为了这个功能,不惜安装各种重量级的截屏软件,甚至四处下载各种 ...
- 知乎模拟登录,支持验证码和保存 Cookies
import requests import time import re import base64 import hmac import hashlib import json import ma ...
- pytest框架,使用print在控制台输入
代码示例: import pytest@pytest.fixture(autouse=True,scope='session') #autouse=True,scope='session'def se ...
- Java基础 -4.6
循环嵌套 乘法口诀表 public static void main(String[] args) { for(int x =1;x<10;x++) { for(int y=1;y<=x; ...
- C#的 IComparable 和 IComparer接口及ComparableTo方法的 区别(非常重要)
(1)https://blog.csdn.net/ios99999/article/details/77800819 C# IComparable 和 IComparer 区别 (2)https:// ...