2020牛客多校第九场 解题报告(AEFIK)

题目链接:https://ac.nowcoder.com/acm/contest/5674#question
A-Groundhog and 2-Power Representation 题意

  • 求表达式的值
  • 只有2 0 + ( ) 组成
  • 2(0)表示2的0次
思路
  • 用python写非常方便
  • 写个x(i)函数表示2的幂次,然后将字符串中的"2("字符替换成"x("
  • 最后调用eval函数将字符串变成有效的表达式求值并返回结果
AC代码
def x(i): return 2**i str = input() str = str.replace("2(","x(") print(eval(str))

E-Groundhog Chasing Death 题意
  • 2020牛客多校第九场 解题报告(AEFIK)
    文章图片
    mod 998244353的结果
思路
  • 唯一分解定理:任何数都可以表示成质因子幂次相乘的形式。2020牛客多校第九场 解题报告(AEFIK)
    文章图片
    ,2020牛客多校第九场 解题报告(AEFIK)
    文章图片
  • gcd(n,m)=2020牛客多校第九场 解题报告(AEFIK)
    文章图片
  • 因为2020牛客多校第九场 解题报告(AEFIK)
    文章图片
    ,所以设p是n,m共有的质因子,k1和k2是n,m对于p的幂次,则就是求解2020牛客多校第九场 解题报告(AEFIK)
    文章图片
    (p是n,m共有的质因子)
  • 优化一个for,找到k1*i和k2*j的零界点sh,sh=k1*i/k2,此时j在sh左边的时候,min总是取k1*i,由于此时的i不变,直接乘数量就好了;j在sh右边的时候,min总是取k2*j,由于j在变,不过就是对等差数列求和。
  • 数规模会很大,取模太多又感觉很烦,其他人是通过欧拉降幂优化,我门就很莽,直接__int128冲,最后取模!!
AC代码
#include #define LL long long #define sc(a) scanf("%d", &a) #define sc2(a, b) scanf("%d%d", &a, &b) #define sc3(a, b, c) scanf("%d%d%d", &a, &b, &c) #define scl(a) scanf("%lld", &a) #define scl2(a, b) scanf("%lld%lld", &a, &b) #define ss(a) scanf("%s", a) #define mem(a, b) memset(a, b, sizeof(a)) #define PII pair #define ll __int128 using namespace std; const ll mod = 998244353; inline void print(__int128 x) { if (x < 0) { x = -x; putchar('-'); } if (x > 9) print(x / 10); putchar(x % 10 + '0'); } template inline void read(_Tp &x) { char ch; bool flag = 0; x = 0; while (ch = getchar(), !isdigit(ch)) if (ch == '-') flag = 1; while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); if (flag) x = -x; } inline ll POW(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } map num1; //存放x质因子和需要幂的数ai map num2; //存放y质因子和需要幂的数bi map ans; //共同质因子和需要幂的数 int main() { ll a, b, c, d, x, y; read(a); read(b); read(c); read(d); read(x); read(y); for (ll i = 2; i * i <= x; i++) //x质因子分解 if (x % i == 0) { int cnt = 0; while (x % i == 0) cnt++, x /= i; num1[i] = cnt; } if (x != 1) num1[x] = 1; for (ll i = 2; i * i <= y; i++) //y质因子分解 if (y % i == 0) { int cnt = 0; while (y % i == 0) cnt++, y /= i; num2[i] = cnt; } if (y != 1) num2[y] = 1; for (auto p : num1) { if (!num2[p.first]) continue; ll pi = p.first, k1 = p.second, k2 = num2[pi]; for (ll i = a; i <= b; i++) { ll sh = k1 * i / k2; //j从1到sh,min都是k1*i; //j大于sh,min都是k2*j if (sh < c) ans[pi] += k1 * i * (d - c + 1); else if (sh >= d) ans[pi] += k2 * (c + d) * (d - c + 1) / 2; //等差数列求和 else ans[pi] += k1 * i * (d - sh) + k2 * (sh + c) * (sh - c + 1) / 2; } } ll res = 1; for (auto p : ans) //所有共同质因子幂次累乘 res = res * POW(p.first, p.second) % mod; print(res % mod); system("pause"); return 0; }

F-Groundhog Looking Dowdy 题意
  • 给定n天,每天生产ki件衣服,选择m件来自不同天的衣服,求最大价格和最小价格的最小差值
  • 数据范围:1<=aij<=1e9,1<=n<=1e6,1<=m<=n,sum of clothes<=2e6,k>=1
思路
  • 尺取法。
  • 首先结构体存衣服生产日期和价格,按照价格从小到大排序。
  • l,r分别是左右端点,当区间内衣服不同生产日期数num没有超过m时,r++;
  • 等于m时,更新左右端点价格差值的最小值 ,l++,直到num
AC代码
#include #define LL long long #define sc(a) scanf("%d", &a) #define sc2(a, b) scanf("%d%d", &a, &b) #define sc3(a, b, c) scanf("%d%d%d", &a, &b, &c) #define scl(a) scanf("%lld", &a) #define scl2(a, b) scanf("%lld%lld", &a, &b) #define ss(a) scanf("%s", a) #define mem(a, b) memset(a, b, sizeof(a)) #define PII pair using namespace std; const double pi = acos(-1.0); const int mod = 1e9 + 7; const int maxn = 1e6+5; const int inf = 0x3f3f3f3f; struct node{ int val,id; bool operator < (const node &a)const{ return val

由于数据给的弱,以下代码可以水过去,要不是敲得慢,差点拿一血QAQ
#include #define LL long long #define sc(a) scanf("%d", &a) #define sc2(a, b) scanf("%d%d", &a, &b) #define sc3(a, b, c) scanf("%d%d%d", &a, &b, &c) #define scl(a) scanf("%lld", &a) #define scl2(a, b) scanf("%lld%lld", &a, &b) #define ss(a) scanf("%s", a) #define mem(a, b) memset(a, b, sizeof(a)) #define PII pair using namespace std; const int maxn = 2e5+5; const int inf = 0x3f3f3f3f; int main(){ int n,m; sc2(n,m); vectorv; while(n--){ int k,x,mii=inf; sc(k); while(k--){ sc(x); mii=min(mii,x); } v.push_back(mii); //每天取最便宜的 } sort(v.begin(),v.end()); //从小到大排 cout<

I-The Crime-solving Plan of Groundhog 题意
  • 给一个序列仅包含数字,让你将其打乱次序并组合成两部分,使这两部分组成的数字相乘得到的结果最小
  • 不允许任何一部分组成的数字包含前导零
思路
  • 大数运算。 两位乘两位的数字一定比一位乘三位的数字大。证明过程如下:
  • (10a+d)*(10b+c)=100ab+10ac+10bd+cd
  • (100b+10c+d)*a=100ab+10ac+ad<(10a+d)*(10b+c)
  • 组合成1位数乘n-1位数
  • 1位数是除零外最小的
  • n-1位数是第一位是除零最小,接着是从小到大加入
  • 然后是模拟乘法运算。
AC代码
#include #define LL long long #define sc(a) scanf("%d", &a) #define sc2(a, b) scanf("%d%d", &a, &b) #define sc3(a, b, c) scanf("%d%d%d", &a, &b, &c) #define scl(a) scanf("%lld", &a) #define scl2(a, b) scanf("%lld%lld", &a, &b) #define ss(a) scanf("%s", a) #define mem(a, b) memset(a, b, sizeof(a)) #define PII pair using namespace std; const int maxn = 1e5+5; int cnt[maxn],a[maxn]; int main(){ int t; sc(t); while(t--){ int n,x; sc(n); mem(cnt,0); //数组清零 for(int i=1; i<=n; i++){ sc(x); cnt[x]++; } int bas=0,ca=0; for(int i=1; i<10; i++){//找第一个非零 if(cnt[i]){ bas=i; cnt[i]--; break; } } for(int i=1; i<10; i++){//找第一个非零 if(cnt[i]){ a[++ca]=i; cnt[i]--; break; } } for(int i=0; i<10; i++){//从小到大加入 if(cnt[i]){ while(cnt[i]--){ a[++ca]=i; } } } string b; for(int i=ca; i>=1; i--){//从个位开始乘 t+=bas*a[i]; b+=t%10+'0'; //存余数 t/=10; //进位 } if(t)b+=t+'0'; //最后进位 reverse(b.begin(),b.end()); //字符串反转 cout<

K-The Flee Plan of Groundhog 题意
  • 有n个结点,n-1条边,小A从1号结点出发前往n号结点看望小B,每秒能走一条路
  • t秒钟之后小B从n结点出发,来追小A,每秒能走两条路
  • 问最迟要多久才能相遇
思路
  • 以n结点为根dfs递归建树。pre数组存放父节点,dep数组存放结点的深度,maxd数组存放子节点最深深度。
  • n个结点,n-1条边,说明这是一棵树,所以小A从1出发去n只有一条路径,t秒之后小A的位置可以计算出来 。
  • 求的是最迟相遇时间,那么小A就要远离小B,往树的深处跑,那么就有两种情况。
  • 第一种情况,小A还没到树的最深处就被小B追上了。因为小B速度是小A的两倍,那么追逐时间其实就是两人的深度之差。
  • 第二种情况,小A到最深处等小B。那么追逐时间就是小B到达最深处的时间。
AC代码
#include #define LL long long #define sc(a) scanf("%d", &a) #define sc2(a, b) scanf("%d%d", &a, &b) #define sc3(a, b, c) scanf("%d%d%d", &a, &b, &c) #define scl(a) scanf("%lld", &a) #define scl2(a, b) scanf("%lld%lld", &a, &b) #define ss(a) scanf("%s", a) #define mem(a, b) memset(a, b, sizeof(a)) #define PII pair using namespace std; const int maxn = 1e5+5; vectorv[maxn]; int pre[maxn],dep[maxn],maxd[maxn]; void add(int a,int b){ v[a].push_back(b); v[b].push_back(a); } void dfs(int s,int fa){//dfs建树 for(auto i:v[s]){//遍历子树 if(i==fa)continue; //不必跑父节点 pre[i]=s; //存放父节点 dep[i]=dep[s]+1; //子节点的深度等于父节点深度加1 maxd[i]=dep[i]; //存放子节点最深深度 dfs(i,s); //向下递归 maxd[s]=max(maxd[s],maxd[i]); //递归到根节点时,从下到上更新子节点最深深度 } } int main(){ int n,t; sc2(n,t); for(int i=1; i

【2020牛客多校第九场 解题报告(AEFIK)】

    推荐阅读