A 打怪
题目描述戳我传送
你是一个勇士,现在你准备去森林刷毛球怪,你有两个属性(血量,攻击力),毛球怪也有这两个属性。当你遭遇一只毛球怪时你们会进入战斗,然后你和毛球怪轮流攻击(你先手),每次使对方的血量减去自己攻击力的数值,当一方的血量小于等于 0 时死亡。现在你想知道在自己活着的前提下最多杀死几只毛球怪。
输入描述
第一行一个正整数t,代表测试数据组数。
第二行四个正整数h,a,H,A,代表你的血量和攻击力以及毛球怪的血量和攻击力。
所有整数大小不超过1000。
输出描述
共 t 行,每行一个整数x,代表最多能杀死多少毛球怪。如果能杀死无数只,输出-1。
思路
因为是自己先出手,所以只要自己的攻击力 a 大于小怪的血量或者小怪攻击力为0打怪就不会扣血如果是这种情况输出-1就好。其他的情况就算出每回合扣的血量就好,注意如果自己的血量h是每回合扣的血的倍数大的小怪数要减一。
代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define INF 1e8 const int mod = 1e9+7; const int maxn = 1e5+5; #define iss ios::sync_with_stdio(false) inline ll read(){ ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } int main(){ int t; cin>>t; int h,a,H,A; while(t--){ cin>>h>>a>>H>>A; int ans = 0; if(a>=H || A == 0) cout<<-1<<endl; else{ int ans = H/a;//需要多少回合击杀小怪 if( H % a ) ++ans;//注意整数的除法 int cnt = h/((ans-1)*A); if(h%((ans-1)*A)==0) cnt-=1;//如果血量是每回合少血的倍数 cout<<cnt<<endl; } } }
B 吃水果
题目描述戳我传送
最近米咔买了n个苹果和m个香蕉,他每天可以选择吃掉一个苹果和一个香蕉(必须都吃一个,即如果其中一种水果的数量为0,则他不能进行这个操作),或者使用魔法将某一种水果的数量翻倍。
现在米咔想吃西瓜了,但是他的主人赛小息不让他买新水果,除非苹果和香蕉没有了,即数量都是0了。
现在米咔想知道,最少用多少天他可以吃光苹果和香蕉。
可以证明的是,一定存在一种方案可以让米咔在若干天后吃光苹果和香蕉。
输入描述
第一行一个正整数T(T≤100),代表数据组数。
接下来T行每行两个正整数n,m(n,m ≤100000)。
输出描述
共T行,每行一个正整数代表答案。
思路
两种水果必须同时吃,而且增加水果数量要消耗一天,所以要尽量少的翻倍(心证),而且不能让一种水果数量太多,所以就是在少的水果为多的一半以下增加,于是给出代码:
代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define INF 1e8 const int mod = 1e9+7; const int maxn = 1e5+5; #define iss ios::sync_with_stdio(false) inline ll read(){ ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } int main(){ int t; cin>>t; int n,m; while(t--){ cin>>n>>m; int ans = 0; if(m>n) swap(n,m); while(n){ ++ans; if(n>=2*m) m *= 2; else { --m;--n; } } cout<<ans<<endl; } }
C 四个选项
题目描述戳我传送
众所周知,高考数学中有一个题目是给出12个单项选择,每一个选择的答案是 A,B,C,D 中的一个。
网上盛传答案存在某种规律,使得蒙对的可能性大大增加。于是今年老师想让你安排这12个题的答案。但是他有一些条件,首先四个选项的数量必须分别为 na,nb,nc,nd。其次有 m 个额外条件,分别给出两个数字 x,y,代表第 x 个题和第 y 个题的答案相同。 现在你的老师想知道,有多少种可行的方案安排答案。
输入描述
第一行五个非负整数na,nb,nc,nd,m,保证na+nb+nc+nd=12,0≤m≤1000。
接下来m行每行两个整数x,y(1≤ x,y ≤12)代表第x个题和第y个题答案必须一样。
输出描述
仅一行一个整数,代表可行的方案数。
思路
用n【i】来存A,B,C, D四个选项的数量 并查集合并必须是相同选项的题目 接下来直接dfs爆搜即可
代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define INF 1e8 const int mod = 1e9+7; const int maxn = 1e5+5; #define iss ios::sync_with_stdio(false) inline ll read(){ ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } int sum[15],fa[15]; int n[5],m; int cnt = 0;//有多少独立的题目 ll ans = 0; int findd(int x){ return fa[x] == x ? x : (fa[x] = findd(fa[x])); } void init(){//初始化 for(int i = 0 ; i < 15 ;++i){ sum[i] = 1;fa[i] = i; } } void dfs(int x){ for(int i = 0 ; i < 4 ; ++i){ if(n[i] >= sum[x]){ n[i] -= sum[x]; if(x == cnt-1 ) ++ans;//x就是搜了多少节点如果等于cnt-1表示全部节点都已经分配完,结果加一 else dfs(x+1); n[i] += sum[x];//回退状态 } } } int main(){ init(); cin>>n[0]>>n[1]>>n[2]>>n[3]>>m; sort(n,n+4,greater<int>()); int x,y; while(m--){ cin>>x>>y; int i = findd(x),j = findd(y); fa[i] = j;//并查集合并选项 } for(int i = 1 ; i <= 12 ;++i){ if(findd(i) == i) cnt++;//如果父亲节点是自己那就多了一个独立的节点 else sum[fa[i]]++;//有多少选项必须一样的个数 } sort(sum,sum+15,greater<int>());//在前面的就表示合并后的节点 dfs(0); cout<<ans<<endl; }
D 最短路变短了
题目描述
给定一个有向带权图,其中包括 n个城市,城市编号从1 到n,有向边的编号从 1 到 m,现在有一个人位于城市 1,并且想要到城市n旅游。现在政府正在决定将一条道路反向,这个人想知道在某一指定道路反向的情况到达城市n最短路径长度会不会变短。
保证开始给定的图从城市1可以到达城市n,若边反向后城市1不能到达城市n,我们视为最短路径长度没有变短。
输入描述戳我传送
第一行包括两个整数n,m(1≤n≤100000,1≤m≤200000)
接下来m行每行三个整数u,v,c (1≤u,v≤n, 1≤c≤10^9),分别代表一条有向边的起点,终点和边权。保证没有自环。
接下来一行一个整数q(1≤q≤200000),代表查询组数,查询之间是独立的。
接下来q行每行一个整数x(1≤x≤m),代表询问将第x条边反向后到达城市n的最短路长度会不会变短。
输出描述
共q行,如果最短路变短输出YES,否则输出NO。
思路
这就是个带权值的有向图,问将一条边反向后能不能缩短路径,很明显反向后如果存在最短边那肯定是经过那条被反向的边,直接对比dis1[n]和disn[u]+dis1[v]+w
代码
#include<bits/stdc++.h> #include<string> using namespace std; typedef long long ll; #define INF 1e8 const int mod = 1e9+7; const int maxn = 2e5+5; #define iss ios::sync_with_stdio(false) inline ll read(){ ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } struct Edge{ int v,w,next; }edge[maxn<<1]; int head1[maxn],headn[maxn],top; ll dis1[maxn],disn[maxn]; priority_queue<pair<ll,int> > q; bool f[maxn]; void add(int u,int v,int w,int head[]){//构造带权值的图 edge[top].v = v; edge[top].w = w; edge[top].next = head[u]; head[u] = top++; } void dij(int st,ll dis[],int head[]){//Dij算法 fill( f , f + maxn , 0 ); dis[st]=0; q.push(make_pair(0,st)); while(q.size()){ int u=q.top().second; q.pop(); if(f[u]) continue; f[u]=1; for(int i = head[u];i != -1;i = edge[i].next){ int v = edge[i].v,w=edge[i].w; if(dis[v]>dis[u]+w){ dis[v]=dis[u]+w; q.push(make_pair(-dis[v],v)); } } } } int U[maxn],V[maxn],W[maxn]; int n; bool check(int id){ int u=U[id],v=V[id],w=W[id]; if(dis1[n]<=disn[u]+dis1[v]+w) return false; return true; } int main(){ memset(dis1,0x3f,sizeof(dis1)); memset(disn,0x3f,sizeof(disn)); int m; cin>>n>>m; fill(head1 ,head1+maxn , -1); fill(headn , headn+maxn , -1); top=0; for(int i = 1;i <= m; ++i){ cin>>U[i]>>V[i]>>W[i]; add(U[i],V[i],W[i],head1); add(V[i],U[i],W[i],headn); } dij(1,dis1,head1); dij(n,disn,headn); int q,x; cin>>q; while(q--){ cin>>x; if(check(x)) puts("YES"); else puts("NO"); } }