文章目录
- A. Level Statistics
- B. Middle Class
- C. Circle of Monsters
- D. Minimum Euler Cycle
- E. Divisor Paths
A. Level Statistics
- 题意
给你一个游戏时刻序列,其中每个时刻包含,代表游戏次数和通关次数。需要你判断序列是否合理。
- 解题思路
前一个时刻不能比当前时刻的参数小,并且通关次数的增长要小于游戏次数的增长。 - AC代码
/**
*@filename:A
*@author: pursuit
*@created: 2021-08-13 09:00
**/
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n;
int x,y,p,c;
void solve(){
bool flag = false;
p = c = 0;
for(int i = 1; i <= n; ++ i){
scanf("%d%d", &x, &y);
if(x < p || y < c || y - c > x - p){
flag = true;
}
p = x, c = y;
}
printf("%s\n", flag ? "NO" : "YES");
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d", &n);
solve();
}
return 0;
}
B. Middle Class
- 题意
给你个数,你可以从中选取一些数然后做平均再分配。需要你判断最多有多少数可以
。
- 解题思路
我们自然是想将多出来的分给其他数,那么选取的小于的也是尽量选择大的。所以我们可以对这些数排序,然后依次取前面的的数,知道平均数小于
时则退出,那么前一个则是最大的答案。
- AC代码
/**
*@filename:B
*@author: pursuit
*@created: 2021-08-13 09:35
**/
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n,x,a[N];
void solve(){
sort(a + 1, a + n + 1);
ll sum = 0;
int cnt = 0;
for(int i = n; i >= 1; -- i){
sum += a[i];
cnt ++;
if(1.0 * sum / cnt < x){
cnt --;
break;
}
}
printf("%d\n", cnt);
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%d", &n, &x);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
solve();
}
return 0;
}
C. Circle of Monsters
- 题意
有个环在一起的怪兽,其有生命值
和爆炸伤害
,即会对第
个怪兽产生
的上海。问你要杀死这
个怪兽所需的最小代价。
- 解题思路
我们首先要清楚,如果所有怪兽都要杀死,那杀死每个怪兽必然有要付出的代价就是,而其中必须要有一个怪兽来启动这个环,所以我们需要付出直接代价
找到最小的即可。
- AC代码
/**
*@filename:C
*@author: pursuit
*@created: 2021-08-13 09:42
**/
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 3e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n;
ll a[N],b[N],c[N];
void solve(){
ll sum = 0;
for(int i = 1; i <= n; ++ i){
sum += c[i];//必须要花费的消耗。
}
ll minn = 1e14;
for(int i = 1; i <= n; ++ i){
minn = min(minn,a[i] - c[i]);
}
printf("%lld\n", sum + minn);
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%lld%lld", &a[i], &b[i]);
if(i > 1)c[i] = a[i] - b[i - 1] < 0 ? 0 : a[i] - b[i - 1];
}
c[1] = a[1] - b[n] < 0 ? 0 : a[1] - b[n];
solve();
}
return 0;
}
D. Minimum Euler Cycle
- 题意
给你一个有向完全图,其中有个顶点,你需要使得每条边都走一遍,找到字典序最小的一种方案,并输出
之间的结点。
- 解题思路
根据题意,我们可构造唯一的字典序最小的序列如:。
故我们可将其分成个区间,其中前
个区间的元素是
个。那么根据第
个结点我们则可以确定在第
个区间,而对于每个区间其中形式为
,据此可得。
- AC代码
/**
*@filename:D
*@author: pursuit
*@created: 2021-08-13 12:40
**/
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int t,n;
ll l,r;
ll pre[N];
int cal(ll x){
if(x > pre[n - 1])return 1;//排除特殊情况。
int idx = lower_bound(pre + 1,pre + n + 1,x) - pre;
//那么pre就在idx所管辖的这个区间为 idx idx + 1 idx idx + 2...这种形式。
x = x - pre[idx - 1];
return x & 1 ? idx : x / 2 + idx;
}
void solve(){
for(int i = 1; i <= n; ++ i){
pre[i] = pre[i - 1] + 2 * (n - i);
}
for(ll i = l; i <= r; ++ i){
printf("%d%c", cal(i), " \n"[i == r]);
}
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%lld%lld", &n, &l, &r);
solve();
}
return 0;
}
E. Divisor Paths
- 题意
给你一个数,D的所有因子(包括1和它本身)作为节点构成无向图,对于某两个因子
,
,若
且
为质数,那么x,y之间就存在一条长为
的边,其中
代表
的因子数量。接下来
次询问,每次询问a,b,问a到b之间的最短路径有多少条。
- 解题思路
不难发现,一定会经过
这个点,因为
都整除
。
不断变成
的过程中即是在不断除以质因子,所以我们可以看成
不断变成
的方案数,即是
的质因子的幂次之和的阶乘除以
的每个质因子的幂次的阶乘之和。二者相乘即可。注意我们需要预处理阶乘和结点的方案数,提高效率。
- AC代码
/**
*@filename:E
*@author: pursuit
*@created: 2021-08-13 14:03
**/
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 998244353;
const int INF = 0x3f3f3f3f;
ll d,u,v;
int q,fac[N];
map<ll,ll> p;
void init(){
//预处理n!
fac[0] = fac[1] = 1;
for(int i = 2; i < N; ++ i){
fac[i] = 1LL * fac[i - 1] * i % P;
}
}
ll ksm(ll n,ll q){
ll ans = 1;
while(q){
if(q & 1)ans = ans * n % P;
n = n * n % P;
q >>= 1;
}
return ans;
}
ll cal(ll x){
//需要计算x到y的所有最短路径,而其都经过gcd(x,y)。
//x移动到gcd(x,y)的最短路径,就是x除以x/(gcd(x,y))的质因子,除的顺序是任意的。
ll sum1 = 0,sum2 = 1;
for(ll i = 2; i * i <= x; ++ i){
if(x % i == 0){
ll num = 0;
while(x % i == 0){
x /= i;
num ++;
}
sum2 = sum2 * ksm(fac[num], P - 2) % P;//除法取模边乘法。
sum1 += num;
}
}
if(x > 1){
sum1 ++;
}
sum1 = sum2 * fac[sum1] % P;
return sum1;
}
void solve(){
for(ll i = 1; i * i <= d; ++ i){
if(d % i == 0){
p[i] = cal(i);
p[d / i] = cal(d / i);
}
}
while(q -- ){
scanf("%lld%lld", &u, &v);
ll k = __gcd(u,v);
printf("%lld\n", p[u / k] * p[v / k] % P);
}
}
int main(){
init();
scanf("%lld%d", &d, &q);
solve();
return 0;
}