2019年CCPC秦皇岛站部分题解
前言
感觉这套题有点难度,相比之下博主是真的菜狗。
不过只要lm队长讲明白MUV LUV EXTRA,欢姐绝杀掉Forest Program ,我再去挨个折磨,就等于菜狗博主的大胜利!
Decimal(数论)
比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6734
题目大意
给出一个整数nnn,问1n\frac{1}{n}n1是否是一个无限小数。
思路
若nnn为222的mmm次幂(m>=0m>=0m>=0)或者是由aaa个222与bbb个555相乘而得,则1n\frac{1}{n}n1为有限小数。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;int main()
{int t;cin>>t;while(t--){int n;cin>>n;while(n%2==0){n/=2;}while(n%5==0){n/=5;}if(n==1) cout<<"No"<<endl;else cout<<"Yes"<<endl;}
}
Invoker(动态规划)
比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6739
题目大意
在游戏Dota2中有一个角色叫做Invoker
,他有三个基础技能:Quas
,Wex
,Exort
。
Invoker
拥有三个元素槽,游戏开始的时候元素槽是空的。
- 当
Invoker
使用Quas
技能时,他会获得Q
元素; - 当
Invoker
使用Wex
技能时,他会获得W
元素; - 当
Invoker
使用Exort
技能时,他会获得E
元素;
当元素槽充满元素时,下一次释放技能所获得的元素会顶替掉元素槽中获得时间最早的元素。
除了这三个基础技能之外,Invoker
还有101010个特殊技能。每个特殊技能都有对应的三种元素:
- 急速冷却
Cold Snap
,需要元素QQQ
,用 Y 表示; - 幽灵漫步
Ghost Walk
,需要元素QQW
,用 V 表示; - 寒冰之墙
Ice Wall
,需要元素QQE
,用 G 表示; - 电磁脉冲
EMP
,需要元素WWW
,用 C 表示; - 强袭飓风
Tornado
,需要元素QWW
,用 X 表示; - 灵动迅捷
Alacrity
,需要元素WWE
,用 Z 表示; - 阳炎冲击
Sun Strike
,需要元素EEE
,用 T 表示; - 熔炉精灵
Forge Spirit
,需要元素QEE
,用 F 表示; - 混沌陨石
Chaos Meteor
,需要元素WEE
,用 D 表示; - 超震声波
Deafening Blast
,需要元素QWE
,用 B 表示;
如果玩家想要释放特殊技能MMM,则需要先将Invoker
的元素槽调整为特殊技能MMM所需要的元素类型,然后按下RRR键使用元素祈唤融合自身所获得的元素,即可释放特殊技能MMM。
三个基础技能分别对应三个独立的按键,每次释放特殊技能时都需要按下RRR键。元素在被用于释放特殊技能之后并不会消失,时间顺序也不会改变。
游戏开始,系统给出一个特殊技能的释放序列strstrstr,你需要按顺序依次施放出所有的特殊技能。
请问你最少需要按多少次键?
思路
博主本来就不擅长dpdpdp,这还是个描述巨长、情况巨多的dpdpdp。我当时看着题目的时候没想砸桌子,心想这是哪个家伙出的题。
出的真好,大佬喝茶(●’◡’●)。
题目十分有趣,我还为此专门去看了一下Dota2中这个英雄的介绍。
没想到Invoker
的技能真的就是这么多,博主这种手残党怕是玩不来了。
不瞎扯了,我们还是来看题吧。
首先我们要明白Invoker
什么情况下可以释放特殊技能。
如果我们一开始想要释放技能『寒冰之墙』,『寒冰之墙』需要的元素为QQE
。那么就产生一个问题:元素的顺序可以变换吗?比如EQQ
可以释放『寒冰之墙』吗?
答案是可以的,题目中提及到unordered element combination
,意为无序序列
。由此我们可以得知,只要当前的元素槽内的元素和技能所需要的元素相同,元素槽内无论是什么顺序我们都能按下R键释放技能。
紧接着我们假设:按下1键可以释放技能Quas,按下2键可以释放技能Wex,按下3键可以释放技能Exort
。
这样的话使用出每个技能的按键顺序如下所示:
在我们把每个技能的释放转换成数字之后不难看出,一个技能的所有按键方案就是其对应的数字序列的全排列。
这样的话对于特殊技能MMM来说,我们至少获取它的一种释放方式,才能通过全排列把所有的按键方案都求出来。很显然,题目中已经给我们了:
那么我们需要设计一个函数,用于获取到要使用的特殊技能所需要使用的一种按键方案:
int press[5]; //press[1]:第一个按键 ,press[2]:第二个按键 ,press[3]:第三个按键void init(int pos)//按照题目中已经给出的按键方案更新press数组的值
{if(str[pos]=='Y')press[1]=press[2]=press[3]=1;else if(str[pos]=='V')press[1]=press[2]=1,press[3]=2;else if(str[pos]=='G')press[1]=press[2]=1,press[3]=3;else if(str[pos]=='C')press[1]=press[2]=press[3]=2;else if(str[pos]=='X')press[1]=1,press[2]=press[3]=2;else if(str[pos]=='Z')press[1]=press[2]=2,press[3]=3;else if(str[pos]=='T')press[1]=press[2]=press[3]=3;else if(str[pos]=='F')press[1]=1,press[2]=press[3]=3;else if(str[pos]=='D')press[1]=2,press[2]=press[3]=3;else if(str[pos]=='B')press[1]=1,press[2]=2,press[3]=3;
}
接下来说一下dp数组的含义,dp[i][x][y][z]的值为按照xyz的顺序打完技能序列str中前i个技能所需要的最小操作次数,其中xyz属于第i个技能的按键方案之一。
int dp[maxn][5][5][5];//dp[i][x][y][z]:按照xyz的顺序打出前i个技能所需要的最小操作次数
以样例XDTBVV
举例说明。
第一个技能是『强袭飓风』(X),它的按键方案就有122
、212
、221
(因为R键是必须要按的键,这里省略不说),那么dp[0][1][2][2]=dp[0][2][1][2]=dp[0][2][2][1]=4dp[0][1][2][2]=dp[0][2][1][2]=dp[0][2][2][1]=4dp[0][1][2][2]=dp[0][2][1][2]=dp[0][2][2][1]=4。
(444的原因是一开始元素槽是空的,所以无论如何都要按三次技能键+一次R键,就是444次)
以下为关键部分,把握不住的建议反复看题+看上面的解释。
假设当前我们已经完成了第i
个技能的释放,接下来我们需要去释放第(i+1)
个技能。由于第(i+1)
个技能有多种按键方案,我们需要一一分析。
假设我们要用第(i+1)
个技能的第一种释放方式,例举出接下来所有的按键可能:
一.我们很幸运,释放完第i
个技能之后,元素槽里时间顺序靠后的两个元素正好是第一种释放方式所需要的前两个元素。
此时我们只需要再施放我们缺少的那个元素所对应的技能,紧接着按下RRR键,就可以施放出第(i+1)
个技能。
for(int x=1; x<=3; x++)//枚举元素槽中的第一个元素是哪个dp[pos][press[1]][press[2]][press[3]]=min(dp[pos-1][x][press[1]][press[2]]+2,dp[pos][press[1]][press[2]][press[3]]);
二.运气还行,释放完第i
个技能之后,元素槽里时间顺序中最后一个元素正好是第一种释放方式所需要的第一个元素。
此时我们需要按顺序施放我们缺少的两个元素所对应的技能,紧接着按下RRR键,就可以施放出第(i+1)
个技能。
for(int x=1; x<=3; x++)//枚举元素槽中的第一个元素是哪个for(int y=1; y<=3; y++)//枚举元素槽中的第二个元素是哪个dp[pos][press[1]][press[2]][press[3]]=min(dp[pos-1][x][y][press[1]]+3,dp[pos][press[1]][press[2]][press[3]]);
三.太倒霉了,释放完第i
个技能之后,元素槽里没有可以接着用的,需要我们重新施放技能。
例如当前的元素槽312
,接下来需要的元素及其顺序为333
,那这个312
中没有一个元素会留到下一个技能的施放中(第一个333会被你接下来获取的333顶替掉)。
此时我们就需要按顺序施放第一个按键方案中的三个元素所对应的技能,紧接着按下RRR键,才可以施放出第(i+1)
个技能。
for(int x=1; x<=3; x++)//枚举元素槽中的第一个元素是哪个for(int y=1; y<=3; y++)//枚举元素槽中的第二个元素是哪个for(int z=1; z<=3; z++)//枚举元素槽中的第三个元素是哪个dp[pos][press[1]][press[2]][press[3]]=min(dp[pos-1][x][y][z]+4,dp[pos][press[1]][press[2]][press[3]]);
四.太走运了,第i
个技能和第(i+1)
是同一个技能,好耶ヽ(✿゚▽゚)ノ
此时我们只需要再按下RRR键,就可以施放出第(i+1)
个技能。
dp[i][press[1]][press[2]][press[3]]=min(dp[i][press[1]][press[2]][press[3]],dp[i-1][press[1]][press[2]][press[3]]+1);
由于我们并不知道实际上会发生上面哪种可能,所以我们必须全部考虑到。
void solve(int pos,int cnt) //到第i个字符,假定现在需要按cnt次键
{if(cnt==1){for(int x=1; x<=3; x++)dp[pos][press[1]][press[2]][press[3]]=min(dp[pos-1][x][press[1]][press[2]]+2,dp[pos][press[1]][press[2]][press[3]]);}else if(cnt==2){for(int x=1; x<=3; x++)for(int y=1; y<=3; y++)dp[pos][press[1]][press[2]][press[3]]=min(dp[pos-1][x][y][press[1]]+3,dp[pos][press[1]][press[2]][press[3]]);}else if(cnt==3){for(int x=1; x<=3; x++)for(int y=1; y<=3; y++)for(int z=1; z<=3; z++)dp[pos][press[1]][press[2]][press[3]]=min(dp[pos-1][x][y][z]+4,dp[pos][press[1]][press[2]][press[3]]);}
}for(int j=1; j<=3; j++)
{solve(i,j);//只按R键的情况dp[i][press[1]][press[2]][press[3]]=min(dp[i][press[1]][press[2]][press[3]],dp[i-1][press[1]][press[2]][press[3]]+1);
}
然后就大功告成了,最后遍历最后一个技能所有的按键方案所对应的dp值,找最小即可。
博主比较懒,不想自己枚举出一个技能对应的所有按键方案,所以我就用next_permutation
逃课了。
(因为是求3个数的全排列,所以可以逃课)
do
{/**代码主体**/
}while(next_permutation(press+1,press+4));
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+100;int dp[maxn][5][5][5];//dp[i][x][y][z]:按照xyz的顺序打出第i个技能所需要的最小操作次数
int press[5];
string str;
void init(int pos)
{if(str[pos]=='Y')press[1]=press[2]=press[3]=1;else if(str[pos]=='V')press[1]=press[2]=1,press[3]=2;else if(str[pos]=='G')press[1]=press[2]=1,press[3]=3;else if(str[pos]=='C')press[1]=press[2]=press[3]=2;else if(str[pos]=='X')press[1]=1,press[2]=press[3]=2;else if(str[pos]=='Z')press[1]=press[2]=2,press[3]=3;else if(str[pos]=='T')press[1]=press[2]=press[3]=3;else if(str[pos]=='F')press[1]=1,press[2]=press[3]=3;else if(str[pos]=='D')press[1]=2,press[2]=press[3]=3;else if(str[pos]=='B')press[1]=1,press[2]=2,press[3]=3;
}void solve(int pos,int cnt)
{if(cnt==1){for(int x=1; x<=3; x++)dp[pos][press[1]][press[2]][press[3]]=min(dp[pos-1][x][press[1]][press[2]]+2,dp[pos][press[1]][press[2]][press[3]]);}else if(cnt==2){for(int x=1; x<=3; x++)for(int y=1; y<=3; y++)dp[pos][press[1]][press[2]][press[3]]=min(dp[pos-1][x][y][press[1]]+3,dp[pos][press[1]][press[2]][press[3]]);}else if(cnt==3){for(int x=1; x<=3; x++)for(int y=1; y<=3; y++)for(int z=1; z<=3; z++)dp[pos][press[1]][press[2]][press[3]]=min(dp[pos-1][x][y][z]+4,dp[pos][press[1]][press[2]][press[3]]);}
}
int main()
{while(cin>>str){int len=str.size();for(int i=0; i<len; i++)for(int x=1; x<=3; x++)for(int y=1; y<=3; y++)for(int z=1; z<=3; z++)dp[i][x][y][z]=inf;///初始化第一个技能init(0);do{dp[0][press[1]][press[2]][press[3]]=4;}while(next_permutation(press+1,press+4));for(int i=1; i<len; i++){init(i);int cnt=1;do{for(int j=1; j<=3; j++){solve(i,j);dp[i][press[1]][press[2]][press[3]]=min(dp[i][press[1]][press[2]][press[3]],dp[i-1][press[1]][press[2]][press[3]]+1);}}while(next_permutation(press+1,press+4));//cout<<endl;}int ans=inf;init(len-1);do{ans=min(ans,dp[len-1][press[1]][press[2]][press[3]]);}while(next_permutation(press+1,press+4));cout<<ans<<endl;}
}
Angle Beats(计算几何)
比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6731
题目大意
首先给出n个点的坐标,接下来有q次询问。
每次询问会给出一个新点A,请问在这n+1个点(算上点A),可以组成直角三角形的并含有点A的组合一共有多少种?
思路
大佬的方法https://www.cnblogs.com/carcar/p/11688108.html,看完之后茅塞顿开。
和之前一场ABC的D题类似(放心,那场ABC已经在写了,该有的都会有)。
解题思路从高中时候学过的知识:向量A=(x1,y1)与向量B=(x2,y2)垂直则有x1*x2+y1*y2=0
开始下手。
如果三个点可以形成直角三角形,那么我们要考虑点A在哪个位置:
一.点A为直角点。
二.点A不是直角点。
此时A有两个位置,但是影响吗?不影响,问题不大。
由于数据量很小(n<=2000,q<=2000n<=2000,q<=2000n<=2000,q<=2000),所以我们可以通过枚举直角点的方法来暴力这道题。
关于如何存储向量,大佬的博客里说的很清楚(那场ABC的D题也是这样存就可以)。
最后再说一个点吧,虽然给的时间是15s,但实际跑下来我T了两次。
最后发现是map[]
拖的时间,这就需要找人问一下效率问题了。记得之前有一次就是map.find()
要比我的map[]
快很多。
//T掉的代码
if(mp[getk(-y,x)])ans[i]+=mp[getk(-y,x)];//AC代码(跑了14086ms,相当极限)
if(mp.count(getk(-y,x)))ans[i]+=mp[getk(-y,x)];
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+100;int ans[2050];
pair<int,int> a[2050],b[2050];pair<int,int> getk(int x,int y){int m=__gcd(x,y);x/=m,y/=m;if(x<0) x=-x,y=-y;else if(x==0&&y<0) y=-y;return make_pair(x,y);
}
int main()
{int n,q;while(~scanf("%d%d",&n,&q)){for(int i=1;i<=n;i++)scanf("%d%d",&a[i].first,&a[i].second);for(int i=1;i<=q;i++)scanf("%d%d",&b[i].first,&b[i].second),ans[i]=0;map<pair<int,int>,int> mp;for(int i=1;i<=q;i++){mp.clear();for(int j=1;j<=n;j++){int x=a[j].first-b[i].first;int y=a[j].second-b[i].second;mp[getk(x,y)]++;if(mp.count(getk(-y,x)))ans[i]+=mp[getk(-y,x)];}}for(int i=1;i<=n;i++){mp.clear();for(int j=1;j<=n;j++){if(i==j) continue;int x=a[i].first-a[j].first;int y=a[i].second-a[j].second;mp[getk(x,y)]++;}for(int j=1;j<=q;j++){int x=b[j].first-a[i].first;int y=b[j].second-a[i].second;if(mp.count(getk(-y,x)))ans[j]+=mp[getk(-y,x)];}}for(int i=1;i<=q;i++)printf("%d\n",ans[i]);}
}
后话
感谢阅读,希望能对你产生一点用处。
以下台词取自《银魂:完结篇·永远的万事屋》:
(如果心情不好,就去看银魂。一集不够就看一个篇章,还是不够就去看剧场版。)
"我应该背负的罪业" "不管重来多少次我都会背负给你看" "你们那些下三滥的诅咒" "不管多少次我都会承受给你看" "不论你们打算诅咒我多少次" "不管这双手打算毁灭这世界多少次" "我的世界,也不会毁灭的" "就凭你们的诅咒,和我这背负罪业的双手" "是无法分开我和这帮蠢朋友的"
吾日三省吾身:日更否?刷题否?快乐否? 更新了,但不是日更;已刷;激动 路漫漫其修远兮,吾将上下而求索
2019年CCPC秦皇岛站部分题解相关推荐
- 2018 CCPC秦皇岛站日记
三题93名铜前,还可以 9/25 明天就要去秦皇岛了,感觉好,麻烦啊...这里就不激动了,因为要忙好多东西. 首先是我准备了几天的模板,因为第一次比赛的原因,所以我也是第一次准备这种比较正式的模板.除 ...
- Riddle(2018 CCPC (秦皇岛站) I 题)
Problem Description Input Output Sample Input 3 3 1 1 1 5 1 1 2 2 3 10 1 2 3 4 5 6 7 8 9 10 Sample O ...
- MUV LUV UNLIMITED(ccpc 秦皇岛2019)
MUV LUV UNLIMITED(ccpc 秦皇岛2019) 题目描述 There are few entertainments in United Nations 11th Force, Paci ...
- 【2022 CCPC 桂林站 日志】部分题解
[2022 CCPC 桂林站] 蒟蒻侥幸铜(打铁原地退役算了 赛前看着参赛队伍大名单就感觉够呛,不少985/211等强校一队,rank+=n.实际战况确实如此,一边开题一边感慨这么多细节怎么这么多队直 ...
- CCPC秦皇岛gym102361A. Angle Beats
CCPC秦皇岛gym102361A. Angle Beats 题意: 给你n个点的坐标,现在有q次询问,每次询问给你一个坐标,问这个坐标可以与给定的n个点组成多少个不同的直角三角形 n<=200 ...
- 2020 CCPC 绵阳站 J-Joy of Handcraft (调和级数 线段树)
2020 CCPC 绵阳站 J-Joy of Handcraft (调和级数 线段树) 之前一直对线段树有种恐惧感,感觉十分晦涩难懂,但是我还是得迎男而上!这题必须补!我说的!耶稣都留不住! 题目 h ...
- 【超好懂的比赛题解】2020ICPC澳门站 个人题解
title : 2021ICPC澳门站 个人题解 date : 2022-10-6 tags : ACM,题解,练习记录 author : Linno 2020ICPC澳门站 个人题解 题目链接:ht ...
- 勇夺四冠,风行游艇在2022 CCPC专业站中展现超群实力
8月28日,经过激烈角逐,为期三天的2022 CCPC中国量产车大赛专业站圆满落幕,在强敌环伺的赛事中,风行游艇脱颖而出,强势摘得四个比赛项目小组第一名,再次印证了卓越的产品实力. 征战2022 CC ...
- 第五届河南省CCPC河南省省赛题解+复盘
第五届河南省CCPC河南省省赛题解+复盘 今年省赛相当有意思的一点,是20级第一次线下省赛,对于部分队也可能是最后一次,看队名就能看出来很多 考研就业的选手,一群老年人在这PK,氛围挺不错. A - ...
最新文章
- Unity与C#创建一个3D平台游戏 Learn to Create a 3D Platformer Game with Unity C#
- Nature:手机1秒生成3D全息图;MIT团队新作,索尼投钱支持
- 在Eclipse中制作SSH配置文件提示插件
- 小知识一、让Swift继续用OC#warning效果
- java集合(List,Set,Map)详细总结
- 阿里云centos7通过yum安装 Mysql 8.0.11
- pytorch 笔记:DataLoader 扩展:构造图片DataLoader
- python中str和repr_python中str()和repr()函数的区别
- OpenCV中的随机数
- http和restful知识点查阅
- python 埋点_scala spark 埋点统计_spark—1:WordCount(Python与Scala对照)
- 对话(Dialog)
- Jquery关闭离开页面时提醒
- 易优CMS插件大全-采集翻译发布插件
- 第十五章 项目收尾与验收
- word如何导出PDF格式
- 【软件构造】正则表达式合法性检测
- 数学规划模型(一):数学规划模型的基本知识
- oracle的跨会话变量,oracle 回话环境变量 userenv ,oracle connetion context 会话环境 连接的会话环境...
- 什么?!NEON还要优化?
热门文章
- com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method list in the service com.dream.servic
- 联想拯救者R720如何组建双通道内存
- LeetCode股票问题总结java
- Linux查看系统资源信息
- 如何才能成功的创业,创业成功的本质是什么
- unity3d--PlayerPrefs 游戏存档
- 11.02-smbios
- 抽象类与接口有什么异同?
- ESP8266开发之旅 应用篇⑤ WiFi探针
- android支付宝支付微信支付封装,如何在Android App中集成支付宝和微信支付功能