比赛地址

牛客OJ

Pro: 5/5/12

Rank: 161/975

[A] Groundhog and 2-Power Representation

题意&题解

签到题

Python大法好

代码

s=input()
a=s.replace('(','**(')
print(eval(a))

[E] Groundhog Chasing Death

题意

\Pi_{i=a}^{b}\Pi_{j=c}^{d}Gcd(x^{i},y^{j})

题解

先分解质因子,然后计算每个质因子的贡献.如果某个质因子是两个数共有的,就计算一下其指数在哪个范围的时候,gcd的结果取第一个数的因子,以及在哪个范围内取第二个数的因子,累计起来即可.需要卡一下常数.

代码

#pragma GCC optimize(3)
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

#define mo 998244353LL

#define mi(__x,__y) ({ \
        long long int __p=__x,__t=1,__Re=1; \
        for (;__t<=__y;(__t&__y)?__Re=(__Re*__p)%mo:0,__p=(__p*__p)%mo,__t<<=1); \
        __Re; \
    })


long long int a, b, c, d, x, y;
long long int xi[200005], yi[200005], s[50][50];
long long int fx[200005], fxt[200005], fy[200005], fyt[200005];
long long int totx = 0, toty = 0;

long long int ask(int a, int b, int c, int d) {
    long long int ans = 1;
    int st1 = 1, st2 = 1;
    while(st1 <= totx && st2 <= toty) {
        if (fx[st1] < fy[st2]) { st1++; continue; }
        if (fx[st1] > fy[st2]) { st2++; continue; }
        int p = fxt[st1], q = fyt[st2], k = fx[st1];
        if (s[p][q] != -1) {
            ans = (ans * mi(k, s[p][q])) % mo;
            st1++; st2++;
            continue;
        }
        s[p][q] = 0;
        int i, aim = 0;
        for (i = a; i <= b; i++) {
            long long int tp = 1LL * i * p / q;
            if (tp < c) { aim = i;}
            else break;
        }
        if (aim) {
            long long int g1 = (1LL*p*(d-c+1)%(mo-1))*(1LL*(a+aim)*(aim-a+1)/2%(mo-1))%(mo-1)+mo-1;
            ans = (ans * mi(k, g1)) % mo; s[p][q] += g1;
        }
        for (; i <= b; i++) {
            long long int tp = 1LL * i * p / q;
            if (tp < d) {
                long long int gg = (1LL*p*i*(d-tp)%(mo-1))+(1LL*q*(c+tp)*(tp-c+1)/2%(mo-1))+mo-1;
                ans = (ans * mi(k, gg)) % mo; s[p][q] += gg;
            } else {
                long long int g = 1LL*q*(c+d)*(d-c+1)/2%(mo-1)*(b-i+1)%(mo-1)+mo-1;
                ans = (ans * mi(k, g)) % mo; s[p][q] += g;
                break;
            }
        }
        s[p][q] = s[p][q] % (mo-1) + mo - 1;
        st1++; st2++;
    }
    return ans;
}

int main(){
    //freopen("1.txt", "r", stdin);
    scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &x, &y);
    long long int p;
    p = sqrt(x)+1;
    for (int i = 1; i <= 35; i++) for (int j = 1; j <= 35; j++) s[i][j] = -1;
    for (int i = 2; i <= p; i++) {
        if (x==0) break;
        int flag = 0;
        while(x%i==0) {
            xi[i]++; x/=i; flag = 1;
        }
        if (flag) {
            fx[++totx] = i;
            fxt[totx] = xi[i];
        }
    }
    if (x != 1 && x != 0) {
        fx[++totx] = x;
        fxt[totx] = 1;
    }
    p = sqrt(y)+1;
    for (int i = 2; i <= p; i++) {
        if (y==0) break;
        int flag = 0;
        while(y%i==0) {
            yi[i]++; y/=i; flag = 1;
        }
        if (flag) {
            fy[++toty] = i;
            fyt[toty] = yi[i];
        }
    }
    if (y != 1 && y != 0) {
        fy[++toty] = y;
        fyt[toty] = 1;
    }
    //for (int i = 1; i <= totx; i++) printf("%d %d\n", fx[i], fxt[i]);
    //for (int i = 1; i <= toty; i++) printf("%d %d\n", fy[i], fyt[i]);
    long long int ans = ask(a, b, c, d);
    printf("%lld\n", ans);
    return 0;
}

[F] Groundhog Looking Dowdy

题意

n个集合,每个集合中有一些数.现在要从每个集合中取出一个数,然后再从这些数中取出m个,使得这些数的极值差最小.求这个最小值.

题解

二分答案.

把所有数从小到大排序,二分极值差,然后用一个滑动窗口一样的东西遍历排好序的序列,如果在某个时刻窗口中的数来自不同的至少m个集合,就认为该答案合法.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#define l(x) (x<<1)
#define r(x) ((x<<1)|1)
#define IL inline
#define reg register
#define LL long long
#define N 2000010
#define INF 0x3f3f3f3f
using namespace std;

int n,m,i,j,low,high,mid,ans,x,cnt;
int v[N];

struct Data{
    int x,id;
}a[N];

IL int Abs(int x){return (x<0)?-x:x;}
IL void Swap(int &a,int &b){a^=b^=a^=b;}
IL int Min(int a,int b){return (a<b)?a:b;}
IL int Max(int a,int b){return (a>b)?a:b;}

inline bool cmp(const Data &a,const Data &b){return a.x<b.x;}

IL int read(){
    int p=0,f=1;    char    c=getchar();
    while (c<48||c>57)  {if (c=='-')    f=-1;   c=getchar();}
    while (c>=48&&c<=57)    p=(p<<1)+(p<<3)+c-48,c=getchar();
    return p*f;
}

IL bool Check(int x){
    reg int i=0,l=0,r=1,L=0,R=0,sum=0;
    for (i=1;i<=n;i++)  v[i]=0;
    l=r=1;  L=a[1].x;   v[a[1].id]++;   sum=1;
    while (l<cnt){
        while (r<cnt && a[r+1].x-L <= x){
            r++;    v[a[r].id]++;
            if (v[a[r].id]==1)  sum++;
            if (sum>=m){
//              cout<<l<<" "<<r<<" "<<x<<endl;
                return 1;
            }
        }
        v[a[l].id]--;
        if (!v[a[l].id])    sum--;
        l++;    L=a[l].x;
        if (r<l){
            v[a[l].id]++;
            if (v[a[l].id]==1)  sum++;
            r=l;
        }
    }
    return 0;
}

int main(){
    #ifdef __Marvolo
    freopen("zht.in","r",stdin);
    freopen("zht.out","w",stdout);
    #endif
    n=read();   m=read();
    if (m==1){
        puts("0");  return 0;
    }
    for (i=1;i<=n;i++){
        x=read();
        for (j=1;j<=x;j++){
            ++cnt;
            a[cnt].x=read();    a[cnt].id=i;
        }
    }
    sort(a+1,a+1+cnt,cmp);
    a[cnt+1].x=0x7f7f7f7f;
    low=0;  high=INF;
    while (low<=high){
        mid=(low+high)>>1;
        if (Check(mid)) ans=mid,high=mid-1;
        else low=mid+1;
    }
    cout<<low<<endl;
//  cout<<ans<<endl;
    return 0;
}

[I] The Crime-solving Plan of Groundhog

题意

给出n个数,要求把它们拼成两个数,使得这两个数的积最小.

题解

贪心.第一个数是一个一位数,为给出的数中最小的数.剩下的数按照从小到大的次序排成第二个数.注意不要带前导零.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#define l(x) (x<<1)
#define r(x) ((x<<1)|1)
#define IL inline
#define reg register
#define LL long long
#define N 100010
#define INF 0x3f3f3f3f
using namespace std;

int T,n,i,x,len;
int a[N],s[15],Ans[N*4];

IL int Abs(int x){return (x<0)?-x:x;}
IL void Swap(int &a,int &b){a^=b^=a^=b;}
IL int Min(int a,int b){return (a<b)?a:b;}
IL int Max(int a,int b){return (a>b)?a:b;}

IL int read(){
    int p=0,f=1;    char    c=getchar();
    while (c<48||c>57)  {if (c=='-')    f=-1;   c=getchar();}
    while (c>=48&&c<=57)    p=(p<<1)+(p<<3)+c-48,c=getchar();
    return p*f;
}

int main(){
    #ifdef __Marvolo
    freopen("zht.in","r",stdin);
    freopen("zht.out","w",stdout);
    #endif
    T=read();
    while (T--){
        n=read();
        for (i=1;i<=n;i++)  a[i]=read();
        if (n==2){
            printf("%d\n",a[1]*a[2]);
            continue;
        }
        len=0;  x=0;
        memset(s,0,sizeof(s));
        for (i=1;i<=n;i++)  s[a[i]]++;
        for (i=1;i<=9;i++)
            if (s[i]){
                x=i;    s[i]--; break;
            }
        for (i=1;i<=9;i++)
            if (s[i]>0){
                s[i]--; Ans[++len]=i;
                break;
            }
        if (s[0]){
            while (s[0]--)  Ans[++len]=0;
        }
        for (i=1;i<=9;i++)
            if (s[i]>0){
                while (s[i]--)  Ans[++len]=i;
            }
        reverse(Ans+1,Ans+1+len);
        for (i=1;i<=len;i++)    Ans[i]*=x;
        for (i=1;i<=len;i++)
            if (Ans[i]>=10) Ans[i+1]+=Ans[i]/10,Ans[i]%=10;
        if (Ans[len+1]) ++len;
        for (i=len;i;i--)   printf("%d",Ans[i]);
        putchar(10);
        for (i=len;i;i--)   Ans[i]=0;
    }
    return 0;
}

[K] The Flee Plan of Groundhog

题意

有两个人在一棵树上玩追逐战,追人的那个速度是2个节点每秒,被追的那个是1个节点每秒.假如两个人都采用最优策略,求被追的人最晚会在什么时候被抓住.

题解

以追人的位置为根建树.显然,被追的人的逃跑路线一定是先从当前位置沿父节点走到某个节点上,然后一直走到该节点最深的儿子的位置.所以预处理下每个节点最深的儿子有多深,然后从被追的人的位置往上枚举即可.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#define l(x) (x<<1)
#define r(x) ((x<<1)|1)
#define IL inline
#define reg register
#define LL long long
#define N 100010
#define INF 0x3f3f3f3f
using namespace std;

int n,i,t,lsum=1,x,y,now,ans,Ans,L;
int head[N],dis[N][2],d[N],h[N],f[N];

vector <int> son[N];

struct Edge{
    int t,next,l;
}e[N*8];

inline void Add(int s,int t){
    e[lsum].t=t;    e[lsum].next=head[s];   head[s]=lsum++;
}

IL int Abs(int x){return (x<0)?-x:x;}
IL void Swap(int &a,int &b){a^=b^=a^=b;}
IL int Min(int a,int b){return (a<b)?a:b;}
IL int Max(int a,int b){return (a>b)?a:b;}

IL int read(){
    int p=0,f=1;    char    c=getchar();
    while (c<48||c>57)  {if (c=='-')    f=-1;   c=getchar();}
    while (c>=48&&c<=57)    p=(p<<1)+(p<<3)+c-48,c=getchar();
    return p*f;
}

IL void Dfs(int x,int fa,int d,int p){
    reg int i=0;
    dis[x][p]=d;
    for (i=head[x];i;i=e[i].next){
        if (e[i].t==fa) continue;
        Dfs(e[i].t,x,d+1,p);
    }
}

IL void Maketree(int x,int fa){
    reg int i=0;
    h[x]=d[x];
    for (i=head[x];i;i=e[i].next){
        if (e[i].t==fa) continue;
        d[e[i].t]=d[x]+1;   f[e[i].t]=x;
        son[x].push_back(e[i].t);
        Maketree(e[i].t,x);
        h[x]=Max(h[x],h[e[i].t]);
    }
}

IL void DP(int x,int val){
    reg int l=0;
    if (!x) return;
    if (L<=3*val)   return;
    l=h[x]-d[x];
    if (l<=L-3*val){
        ans=l;  l=L-3*val-l;
        ans+=(l+1)>>1;
        Ans=Max(Ans,ans+val);
    }   else 
        Ans=Max(Ans,L-3*val+val);
    DP(f[x],val+1);
}

int main(){
    #ifdef __Marvolo
    freopen("zht.in","r",stdin);
    freopen("zht.out","w",stdout);
    #endif
    n=read();   t=read();
    if (n==1){
        puts("0");  return 0;
    }
    for (i=1;i<n;i++){
        x=read();   y=read();
        Add(x,y);   Add(y,x);
    }
    Dfs(1,0,0,0);   Dfs(n,0,0,1);
    if (dis[n][0]<=t){
        puts("0");  return 0;
    }
    for (i=1;i<=n;i++)
        if (dis[i][0]==t && dis[i][0]+dis[i][1]==dis[n][0]){
            now=i;  break;
        }
    Ans=(dis[now][1]+1)>>1; L=dis[now][1];
    Maketree(n,0);  DP(now,0);
    cout<<Ans<<endl;
    return 0;
}

总结

解题的技巧性还是有待提升,比如B题的策略和国王游戏就比较像,J题0转-1想到了,离化成前缀和模型差了一点点.接下来应该多刷点Atcoder?

说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...