目录
A. ACM(签到)
思路:
代码
B. 贪吃的Diana(签到)
思路
代码
C. 神河霓朝纪(贪心)
思路:
代码
D. 穿袜子(模拟)
思路:
代码:
E. 翻转拼图(状态压缩)(搜索)
思路:
代码:
F. 舞台矩形(ST表)
思路:
代码:
J. RGB (状压tp)
思路:
代码
G. 跳台滑雪(贪心)
思路:
代码:
众所周知,ACM竞赛是计算机领域最具影响力和含金量的比赛,新队员小A与校队牛人小B聊了起来:
小A:师哥,如果我不坚持训练,能在ACM国家级比赛中获得奖牌吗?
小B:不太可能0.0
小A:不太可能是有多不可能?能说的具体一点吗,比如获得铜牌的概率是多少?
小B:其实我已经告诉你了0.0
输入描述:
一个非负整数n(0≤n≤10000),代表小A想知道的不坚持训练能在ACM国家级比赛中获得铜牌概率的精确位数。
输出描述:
0,精确到n位小数。
输入
10
输出
0.0000000000
签到,输入n,输出小数点后n个0
#include
using namespace std;
int main() {
int n;
cin>>n;
if(n==0){
cout<<0;
return 0;
}
printf("0.");
for(int i=0;i
题目描述
小草莓 Diana 同学是众所周知的大胃王,如果每天无法吃够总计 K 饱腹度的外卖,她就会不开心。
今天她的朋友 —— 帅气的 Queen 同学拿到了 Diana 之前 N 天点的所有外卖的外卖单,共计 S 份。
每份外卖单上有两个数字,ni 和 ki ,分别表示这份外卖是 Diana 是在这 N 天里的 第 ni 天点的,且这份外卖饱腹度为 ki 。
现在她想要计算之前 N 天中,Diana有多少天是不开心的,你能帮帮她吗?
输入描述:
第一行输入 N 和 K 和 S,
接下来 S 行,其中第 i 行代表一份外卖单,包含两个整数 ni 和 ki,
表示 Diana 在第 ni 天,吃了一份饱腹度为 ki 的食物。
输出描述:
输出Diana 不开心的天数。
输入
10 5 5 4 6 2 5 3 4 3 1 1 1
输出
7
说明
Queen拿到了之前10天里,Diana的五份食物清单,且Diana每天需要至少吃饱腹度为 5 的食物才能开心。
其中,Diana 在第2天和第3天,都吃到了饱腹度之和为 5 的食物,而在第4天,吃到了饱腹度之和为 6 的食物。
在第1天,Diana 只吃到了饱腹度之和为 1 的食物。
在第5天,第6天,第7天,第8天,第9天,第10天,Diana 没有吃到任何食物。(所以也没有任何清单)
所以,Diana 在之前10天中,只有3天吃饱了,剩下有7天是不开心的。答案为7。
备注:
0 < N,S ≤ 105, 0 ≤ K ≤ 109, 0 < ni ≤ N, 0 ≤ ki ≤ 104
签到,哈希,读入每天的食物后,依次和k比较即可
#include
using namespace std;
typedef long long ll;
ll n,k,s;
ll a[1000005];
int main() {
cin>>n>>k>>s;
while(s--){
ll m,t;
cin>>m>>t;
a[m]+=t;
}
ll ans=0;
for(int i=1;i<=n;i++){
if(a[i]
题目描述
万智牌当中有两种牌。
一种叫 地牌。对于每张你场上的地牌,你可以横置它——这会为你产生 特定颜色的法术力。
另一种叫 咒语牌。对于每张咒语,你需要支付特定颜色的法术力作为费用,才能施放这张咒语。
而法术力总共有五种不同的颜色,白,蓝,黑,红,绿。
具体来说,地牌具有如下效果。当地牌被横置时,可以产生一点卡上标注的颜色的法术力。(例如下图,便是五张不同颜色的单色地牌)
而咒语牌上标注的费用一定由如下两种组成。
特定颜色的法术力 若干点。
任意颜色法术力 若干点。
例如 左下图,指的是该咒语费用为,一点任意颜色的法术力,和四点黑色法术力
例如 右下图,指的是该咒语费用为,三点任意颜色的法术力,和一点白色法术力,一点黑色法术力
现在给定你场上的若干张地牌(每张地牌都可以被横置一次,且最多可以被横置一次)
给定若干张咒语,问你是否能打出所有咒语。
输入描述:
第一行是一个整数T,代表测试数据组数。
对于每组数据:
第一行是一个整数 N,代表你有多少张地牌。
接下来 N 行,每行一个字符串,字符串包含一个大写字母,表示地牌的颜色。共有五种可能的大写字母,W U B G R,分别代表 白 蓝 黑 绿 红。
接下来一行,一个整数M,代表你有多少张咒语牌。
接下来 M 行,每行一个字符串(最长不超过10),字符串包含若干个大写字母,代表咒语的费用及颜色。共有六种可能的大写字母 W U B G R O,分别代表 白 蓝 黑 绿 红 及无色(即任意颜色)。
输出描述:
对于每组测试数据:
一个整行——如果你的地牌足以支付所有的咒语,输出 “YES”。否则输出 “NO”。
输入
7 2 W W 1 WW 4 U W W B 2 BUO W 2 R B 1 ROO 3 B U R 1 RRU 3 R U R 2 RR O 3 U R B 2 UB R 4 R U U W 4 R O W G
输出
YES YES NO NO YES YES NO
备注:
数据保证,0 < T ≤ 200,0 < N ≤ 10000,0 < M ≤ 1000。
对于每个 地牌 字符串,保证为长度为 1 的字符串,且只会包含W U B G R 五种可能的字符。
对于每个 咒语牌 字符串,保证其长度不小于1,不大于10,且只会包含 W U B G R O 六种可能的字符。
简单贪心,把所有必需的牌统计起来,优先使用必需牌,最后看剩余的牌够不够O的个数
#include
using namespace std;
typedef long long ll;
int a[1000],num[1000];
int main() {
int T;
cin>>T;
while(T--){
memset(a,0,sizeof(a));
memset(num,0,sizeof(num));
int n,m;
cin>>n;
while(n--){
char ch;
cin>>ch;
num[ch]++; //统计已有个数
}
cin>>m;
bool flag=1;
while(m--){
string s;
cin>>s;
for(int i=0;i=a['W'])num['W']-=a['W']; //比较必需牌是否充足
else flag=0;
if(num['U']>=a['U'])num['U']-=a['U'];
else flag=0;
if(num['B']>=a['B'])num['B']-=a['B'];
else flag=0;
if(num['G']>=a['G'])num['G']-=a['G'];
else flag=0;
if(num['R']>=a['R'])num['R']-=a['R'];
else flag=0;
if(num['W']+num['U']+num['B']+num['G']+num['R']
题目描述
小K同学有一箱袜子,这些袜子各自有着不同的图案,并且有的袜子只能左脚穿、有的袜子只能右脚穿、还有的袜子左右脚都能穿。每天早上他都必须从箱子里拿出1对配套的袜子穿着出门(配套的袜子必须是图案相同的,并且左脚和右脚各有1只可以穿得上的袜子)。现在告诉你箱子里本质不同(图案不同或者左右脚适配性不同)的袜子各有多少只,小K同学想知道,他最少要从箱子里取出多少只袜子,才可以保证凑齐至少1对配套的袜子?
输入描述:
第一行输入一个正整数N,表示有多少种本质不同的袜子;
接下来的N行,每行输入P,Q,M,其中P是一个非负整数,表示袜子的图案;Q是一个字符,当Q取值为'L'时,表示袜子只适配左脚,当Q取值为'R'时,表示袜子只适配右脚,当Q取值为'*'时,表示袜子同时适配左右脚;M是一个正整数,表示这种袜子共有多少只。
(1<=N<=10^5,0<=P<=10^9,Q ∈\in∈ { 'L' , 'R' , '*' },1<=M<=10^5)
输出描述:
对于每组测试数据,输出1个答案,表示最少取出的袜子数。若无法配对成功,输出-1。
输入
3 0 L 7 0 R 3 1 * 10
输出
9
说明
取出7只图案为0的左脚袜子,取出1只图案为0的右脚袜子,再取出1只图案为1的袜子。
输入
2 10 L 5 7 R 5
输出
-1
非常ex的模拟题,把所有凑不成一对的袜子都加起来,然后+1即可
每种袜子个数为 max(左脚,右脚)+ 1(如果有 * )
#include
using namespace std;
typedef long long ll;
struct node{ //袜子
int p;
char kind;
int num;
}wazi[100005];
bool cmp(node a,node b){
if(a.p!=b.p)return a.p>n;
for(int i=0;i>wazi[i].p>>wazi[i].kind>>wazi[i].num;
}
sort(wazi,wazi+n,cmp);
bool flag=0;
for(int i=0;i1)flag=1; //考虑只有*的情况
if(wazi[i].p==wazi[i+1].p){
flag=1;
break;
}
}
if(!flag){ //特判凑不出来
cout<<-1;
return 0;
}
ll ans=0;
for(int i=0;i
题目描述
给定一个3*3的棋盘,每个格子有正反两面。现定义一种翻转操作:指定一个格子,将该格子和与其上下左右相邻(如果存在)的所有格子一同翻面。对于给定的棋盘初始状态,最少需要几步操作才能将棋盘的所有格子都翻转为正面?
输入描述:
输入一个3*3的矩阵,表示棋盘的初始状态,0表示正面,1表示反面。
输出描述:
输出一个数字,表示最少所需的操作步数。
输入
0 0 0 0 0 0 0 0 0
输出
0
说明
所有格子的初始状态已经是正面,无需翻转
输入
0 1 0 1 1 1 0 1 0
输出
1
说明
对中间格子进行1次翻转操作
输入
0 0 1 1 1 0 0 0 0
输出
2
说明
先对上方格子进行1次翻转操作,再对左上格子进行1次翻转操作
正解emm没想出来,但是一看数据范围很小,直接暴力搜索就过了
一个地方不可能翻转两次(相当于没变),所以用01串表示这九个数是否翻转,类似状态压缩,然后枚举所有状态,看是否符合条件即可
#include
using namespace std;
typedef long long ll;
int a[5][5],b[5][5];
int ans=10000000;
int cnt(int t){ //统计这一状态的翻转次数(01串里1的个数)
int ans=0;
while(t){
if(t%2==1)ans++;
t/=2;
}
return ans;
}
int d[5][2]={0,0,0,1,0,-1,1,0,-1,0}; //记录相邻的四个点和本身
bool check(){ //如果翻转后全部为0,返回1
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
if(a[i][j]%2!=0)return 0;
}
}
return 1;
}
void dfs(int i){ //暴力搜索
for(int i=1;i<=3;i++){ //先初始化数组,新开一个数组,原数组要多次操作不能动
for(int j=1;j<=3;j++){
a[i][j]=b[i][j];
}
}
if((i>>0)%2==1){ //状态压缩,如果在第0位要翻转,相邻的位置都翻转
int x=3,y=3;
for(int j=0;j<5;j++){
a[x+d[j][0]][y+d[j][1]]++;
}
}
if((i>>1)%2==1){ //copy,同理,懒得推通项了
int x=3,y=2;
for(int j=0;j<5;j++){
a[x+d[j][0]][y+d[j][1]]++;
}
}
if((i>>2)%2==1){
int x=3,y=1;
for(int j=0;j<5;j++){
a[x+d[j][0]][y+d[j][1]]++;
}
}
if((i>>3)%2==1){
int x=2,y=3;
for(int j=0;j<5;j++){
a[x+d[j][0]][y+d[j][1]]++;
}
}
if((i>>4)%2==1){
int x=2,y=2;
for(int j=0;j<5;j++){
a[x+d[j][0]][y+d[j][1]]++;
}
}
if((i>>5)%2==1){
int x=2,y=1;
for(int j=0;j<5;j++){
a[x+d[j][0]][y+d[j][1]]++;
}
}
if((i>>6)%2==1){
int x=1,y=3;
for(int j=0;j<5;j++){
a[x+d[j][0]][y+d[j][1]]++;
}
}
if((i>>7)%2==1){
int x=1,y=2;
for(int j=0;j<5;j++){
a[x+d[j][0]][y+d[j][1]]++;
}
}
if((i>>8)%2==1){
int x=1,y=1;
for(int j=0;j<5;j++){
a[x+d[j][0]][y+d[j][1]]++;
}
}
if(check())ans=min(ans,cnt(i));
}
int main(){
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
cin>>b[i][j];
}
}
for(int i=0;i<(1<<9);i++){ //所有状态都考虑一遍
dfs(i);
}
cout<
题目描述
最近,圣翔音乐学园的99期生又要准备今年的圣翔祭了。
在一次舞台排练中,星见纯那同学意外发现,她可以将舞台视作一个平面直角坐标系。而站在舞台上的每位演员同学,都是坐标系当中一个坐标为整数的点。
星见纯那同学还发现,在布置舞台时,假如在舞台上放置一些边平行于舞台轴线的矩形,舞台会变得更加优美。她称这类矩形叫做舞台矩形。换言之,如果把舞台当作平面直角坐标系,那么四条边都平行于坐标轴的矩形便是舞台矩形。
现在星见纯那同学已经拿到了圣翔祭的台本,知道了每一位同学在舞台上的位置。现在她想要知道,对于某一对同学 A 和 B,能覆盖横坐标在A,B之间的所有同学的最小舞台矩形面积是多少。
聪明的星见纯那当然能够算出这个问题的答案,那么你可以算出来吗。
输入描述:
第一行是一个整数 N,代表舞台上演员同学的数量。
接下来N行,每行有两个整数 Xi 和 Yi,代表第 i 位演员在舞台上的坐标为 (Xi , Yi)
接下来一行,一个整数Q,代表询问组数。
接下来Q行,每行两个整数 A 和 B,代表对于该组询问,你需要找到最小满足下面条件的矩形,并输出该矩形的面积:
矩形的四条边都平行于平面直角坐标系的某一条坐标轴。
对于任意 横坐标大于等于 XA (即第 A 位演员的横坐标)且 横坐标小于等于 XB(即第 B 位演员的横坐标)的演员同学,其一定在矩形内部或在矩形的边上。
特别地,如果矩形退化成了一条线段或一个点,视作该矩形面积为 0。
输出描述:
输出 Q 行,每行一个整数 S,代表对应询问的最小矩形的面积是S。
特别地,如果矩形退化成了一条线段或一个点,视作该矩形面积为 0。
示例1
输入
7 1 1 1 -1 1 0 3 5 7 2 -2 -3 4 4 9 7 5 1 1 1 2 6 7 6 5 4 1 1 7 3 4 6 3
输出
6 0 0 48 72 0 18 12 12
备注:
横坐标范围 -1*109 ≤ Xi ≤ 1*109
纵坐标范围 -1*109 ≤ Yi ≤ 1*109
N ≤ 105, Q ≤ 105
基本是个st表模板题,稍微加了点细节,查询时对应下标对应了好久,二分查找要用STL,手写二分有个负数,痛苦死了
区间长度要记得储存,不然乘的是学生编号的差
st表模板这里有——ST表处理RMQ问题模板
#include
using namespace std;
typedef long long ll;
int stmax[100005][25],stmin[100005][25]; //st表存区间最大最小值
int m,n,Log[100005]; //预处理log2[n]
void init(){ //预处理,st表模板
Log[0]=-1;
for(int i=1;i<=n;i++){
if(i&(i-1))Log[i]=Log[i-1];
else Log[i]=Log[i-1]+1;
}
for(int j=1;j<=Log[n];j++){ //st表模板
for(int i=1;(i+(1<>n;
for(int i=1;i<=n;i++){
cin>>stu[i].x>>stu[i].y;
tx[i]=stu[i].x; //记录横坐标
}
sort(stu+1,stu+n+1,cmp);
for(int i=1;i<=n;i++){
a[i]=stu[i].x; //储存排序后第i个学生对于的横坐标,供查询时使用
stmax[i][0]=stu[i].y; //赋值st[i][0]
stmin[i][0]=stu[i].y;
}
init(); //预处理
int Q;
cin>>Q;
while(Q--){
int l,r;
cin>>l>>r; //先输入学生标号
l=tx[l],r=tx[r]; //对应成各自坐标
if(l>=r){ //特判,>是根据样例得出来的
cout<<0<
题目描述
给你一个M*N的网格,用红绿蓝(RGB)三种颜色填充,使得任意两个相邻的格子(上下左右四个方向相邻)颜色不同,请问总共有多少种不同的涂色方案?
结果对1e9+7取模。
输入描述:
第一行输入两个正整数M和N,表示网格的尺寸。
(1<=M<=8,1<=N<=5000)
输出描述:
对于每组测试数据,输出1行答案,包含1个取模后的涂色方案数。
输入
1 3
输出
12
说明
对于1*3的网格,总共有以下12种涂色方案:
RGB,RGR,RBG,RBR,GBR,GBG,GRB,GRG,BGR,BGB,BRG,BRB。
输入
2 2
输出
18
输入
3 5
输出
5118
状压dp,要用3进制存,012代表三种颜色
要全部预处理出来,把符合条件的状态放到vector里,再把两层可以相邻的状态预处理出来放到vector里,T了一发后960ms险过
#include
using namespace std;
typedef long long ll;
ll mod=1e9+7;
int m,n;
bool check1(int t){ //三进制里判断状态是否合法
int tmp=-1; //储存上一位的数
for(int i=0;iv2[10005]; //存放v2[i]存和状态i相邻的状态
int main(){
cin>>m>>n;
int siz=pow(3,m);
vectorv; //存合法状态
for(int i=0;i
题目描述
跳台滑雪是冬奥会历史上最悠久的项目之一。选手踩着滑雪板在跳台上起滑、加速,从跳台末端飞出后,身体前倾沿抛物线在空中飞行,最后落在山坡上。裁判员会根据运动员的飞行距离和动作完成情况评分。
小L同学最近喜欢上了冬奥会的跳台滑雪项目,并且参加了一场线上跳台滑雪比赛。已知跳台选手有N种可以选择的动作姿式,每种动作都有各自的成功率pi与难度分ri,如果成功则获得相应的难度分,如果失败则不得分。小L同学最后一个出场,现在他知道了M个对手的得分ci,以及自己的得分S,他希望自己在完成下一个动作后的名次能够到达前K名(可以与其他人并列第K名)。请问他应该如何选择下一个动作,才能在保证排名小于等于K的前提下,使成功率最大。
输入描述:
第一行输入三个正整数N、M、Q,分别表示可选动作姿式的数量、跳台对手的数量、以及查询的次数;
接下来的N行,每行输入一个浮点数pi和一个正整数ri,分别表示第i个动作的成功率和难度分;
接下来的一行输入M个正整数c1,…,cM,其中ci表示第i个对手目前的得分,保证每个对手的得分不同;
接下来的Q行,每行输入两个正整数S和K,分别表示小L同学目前的得分以及预期的名次。
(1<=N、M、Q<=10^5,0 输出描述: 对于每组测试数据,输出Q行答案,即对于每次查询,输出小L同学要选择的动作的下标(从0开始)。如果有多个符合条件的动作,首先选择分数最高的。如果分数和成功率都相同,选择下标最小的。如果不可能到达目标名次,输出-1。 输入 5 3 2 输出 说明 对于第1次查询,有编号为0、1、2的三种动作可以到达前2名。如果选择编号为0的动作,成功率0.2,得分12.0,排名第2;如果选择编号为1的动作,成功率0.5,得分11.0,排名第2;如果选择编号为2的动作,成功率0.4,得分10.0,排名并列第2。所以选择编号为1的动作成功率最高。 对于第2次查询,不论选择哪个动作,最终得分都不会超过12.0分,所以名次不可能上升到第1名或者并列第1名。 贪心,优先选概率高的动作,将所有得分情况预处理出来,使查询复杂度为O(1) 把所有动作按概率排序,枚举一遍
0.2 10
0.5 9
0.4 8
0.9 7
0.7 2
5 10 15
2 2
2 1
1
-1
思路:
当前动作能获得的分数和之前动作获得的最高分之间的分数 要做的动作为当前动作代码:
#include