E.F(cf div2 Round 66)

E.Ehab and the Expected GCD Problem

題意:對n的一個排列,使這個排列中前綴的不同gcd個數最大,問有多少種這樣的排列?

思路:考慮gcd的衰減,所以第一個數一定有最多的質因子個數。那麼它一定是形如2^x*3^y,(其中y<=1)。因爲任何比3大的質數都至少可以提供2個2,而3^2可以提供3個2。

所以我們可以考慮如下的dp:

dp[i][j][k],i是枚舉到的下標,j是gcd中2個數,k是gcd中3個數。

dp[i+1][x][y]=dp[i+1][x][y]+dp[i][x][y]∗(f(x,y)−i)

dp[i+1][x−1][y]=dp[i+1][x−1][y]+dp[i][x][y]∗(f(x−1,y)−f(x,y))

dp[i+1][x][y−1]=dp[i+1][x][y−1]+dp[i][x][y]∗(f(x,y−1)−f(x,y))dp[i+1][x][y−1]=dp[i+1][x][y−1]+dp[i][x][y]∗(f(x,y−1)−f(x,y))

f(x,y)是n中至少含x個2,y個3的數的數量。

#include <bits/stdc++.h>

using namespace std;
#define N 1000005
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i++)
#define add(a,b) a=((b)+a)%mod
int f[50][2],dp[N][22][3];
int n,m;
int r0(int x){return !x?0:r0(x/2)+1; }
int main()
{
    cin>>n;
    m=r0(n)-1;
    go(i,0,m)f[i][0]=n/(1<<i),f[i][1]=n/(1<<i)/3;
    dp[1][m][0]=f[m][0];
    dp[1][m-1][1]=f[m-1][1];
    go(i,2,n){
        go(j,0,m)
            go(k,0,1)
                add(dp[i][j][k],1ll*dp[i-1][j][k]*max((f[j][k]-i+1),0)%mod),
                add(dp[i][j][k],1ll*dp[i-1][j+1][k]*(f[j][k]-f[j+1][k])%mod),
                add(dp[i][j][k],1ll*dp[i-1][j][k+1]*(f[j][k]-f[j][k+1])%mod);
    }
    cout<<dp[n][0][0]<<endl;
    return 0;
}

 

F.Ehab and the Big Finale

題意:交互。給以一顆根節點爲1的樹,讓你找一個被選定的點x。兩種操作:詢問u到x的距離,詢問u到x路徑上的第二個點(u必須是x的祖先)。

思路:做的時候想了sqrt(n)的思路,後來去看了題解。

首先劃分輕重鏈。首先開始的時候根節點是1,然後詢問根節點重鏈上最後一個結點u與x的距離,判一下如果x在鏈上,那麼x是u的lca,否則找到lca,讓lca到x路徑上的第二個點成爲新的根。,這個點是輕兒子,這樣新的樹的大小一定小於原樹的1/2。

#include <bits/stdc++.h>

using namespace std;
#define N 200005
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i++)
int dep[N],deep[N],fa[N],num[N],son[N],tot,n;
int pri(int x,int f){
    if(f==1)printf("d %d\n",x);
    if(f==2)printf("s %d\n",x);
    if(f==3)printf("! %d\n",x);
    fflush(stdout);
    int res;
    if(f<3)scanf("%d",&res);
    return res;
}
vector<int>path[N];
void  dfs(int u,int fath,int dep){
    deep[u]=dep;
    fa[u]=fath;
    num[u]=1;
    for(auto v:path[u]){
        if(v==fath)continue;
        dfs(v,u,dep+1);
        num[u]+=num[v];
        if(num[v]>num[son[u]] ) son[u]=v;
    }
}
int gettool(int x){

    return x;
}
int u,to;
int main()
{
    cin>>n;
    go(i,2,n)scanf("%d %d",&u,&to),path[u].push_back(to),path[to].push_back(u);
    dfs(1,0,0);
    int dep=pri(1,1),x=1;
    while(deep[x]!=dep){
        while(son[x])x=son[x];
        int k=pri(x,1);
        if(k==deep[x]-dep)while(k--)x=fa[x];
        else {
            k=(k+deep[x]-dep)/2;
            while(k--)x=fa[x];
            x=pri(x,2);
        }
    }
    pri(x,3);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章