1. 程式人生 > 實用技巧 >2020牛客多校第7場賽後感

2020牛客多校第7場賽後感

本部落格主要目的為個人使用,也歡迎讀者討論。

1.題難懂

2.自己傻

3.知識少

A. Social Distancing

題意:在座標系中原點為圓心,r為半徑的圓內放n個點,求$\sum_{i=1}^{n-1} \sum_{j=i+1}^n d(i,j)^2$最大值。選擇的座標是整數座標。$1 \le n \le 8, 1\le r \le 30$

可以用dp。(這個真沒想到,我還以為是貪心)

f[i,x,y]表示用了i個人,x表示橫座標之和,y表示縱座標之和。

那麼$f[i,x,y]=\sum_{i=1}^{n-1} \sum_{j=i+1}^n ((x_i-x_j)^2+(y_i-y_j)^2)=\sum_{i=1}^{n-1} \sum_{j=i+1}^n (x_i^2+x_j^2-2x_ix_j+y_i^2+y_j^2-2y_iy_j)$

可以推出$f[i,x+j,y+k]=max\{f[i-1,x,y]+(i-1)(j^2+k^2)+\frac{f[i-1,x,y]+x^2+y^2}{n-1}-2xj-2yk\}$

如果怕超時的話,可以預處理。

下面是dp的程式碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
using namespace
std; typedef pair<int,int> PII; struct Trip{ int x, y, d; Trip(int x=0, int y=0, int d=0):x(x),y(y),d(d){} }; int n, r; //vector<Trip> f[10]; //vector<int> Pos; int f[10][600][600], base=300; int cal(int x, int r){ if(x<0) x=-x; return sqrt(r*r-x*x); } int main(){ //freopen("A.txt","w",stdout);
for(int i=1; i<=30; ++i){ memset(f,0,sizeof(f)); r=i; for(int n=2; n<=8; ++n){ for(int xi=-300; xi<=300; ++xi){ for(int yi=-300; yi<=300; ++yi){ if(n>2 && f[n-1][xi+base][yi+base]==0) continue; if(n==2 && xi*xi+yi*yi>r*r) continue; for(int xii=-r; xii<=r; ++xii){ int yii_max=sqrt(r*r-xii*xii); for(int yii=-yii_max; yii<=yii_max; ++yii){ f[n][xi+xii+base][yi+yii+base]=max(f[n][xi+xii+base][yi+yii+base],\ f[n-1][xi+base][yi+base]+(n-1)*(xii*xii+yii*yii)+(f[n-1][xi+base][yi+base]+xi*xi+yi*yi)/(n-1)-2*xii*xi-2*yii*yi); } } } } int ans=0; for(int i=-300; i<=300; ++i){ for(int j=-300; j<=300; ++j){ ans=max(ans,f[n][i+base][j+base]); } } printf("\t%d", ans); if(n==8) puts(""); } } getchar(); return 0; }
A dp

下面是打表的程式碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int a[10][40];

int main(){
a[1][1]=0; a[2][1]=4; a[3][1]=8; a[4][1]=16; a[5][1]=24; a[6][1]=36; a[7][1]=48; a[8][1]=64; 
a[1][2]=0; a[2][2]=16; a[3][2]=32; a[4][2]=64; a[5][2]=96; a[6][2]=144; a[7][2]=192; a[8][2]=256; 
a[1][3]=0; a[2][3]=36; a[3][3]=76; a[4][3]=144; a[5][3]=218; a[6][3]=324; a[7][3]=432; a[8][3]=576; 
a[1][4]=0; a[2][4]=64; a[3][4]=130; a[4][4]=256; a[5][4]=384; a[6][4]=576; a[7][4]=768; a[8][4]=1024; 
a[1][5]=0; a[2][5]=100; a[3][5]=224; a[4][5]=400; a[5][5]=624; a[6][5]=900; a[7][5]=1224; a[8][5]=1600; 
a[1][6]=0; a[2][6]=144; a[3][6]=312; a[4][6]=576; a[5][6]=880; a[6][6]=1296; a[7][6]=1740; a[8][6]=2304; 
a[1][7]=0; a[2][7]=196; a[3][7]=416; a[4][7]=784; a[5][7]=1188; a[6][7]=1764; a[7][7]=2356; a[8][7]=3136; 
a[1][8]=0; a[2][8]=256; a[3][8]=554; a[4][8]=1024; a[5][8]=1572; a[6][8]=2304; a[7][8]=3102; a[8][8]=4096; 
a[1][9]=0; a[2][9]=324; a[3][9]=722; a[4][9]=1296; a[5][9]=2014; a[6][9]=2916; a[7][9]=3954; a[8][9]=5184; 
a[1][10]=0; a[2][10]=400; a[3][10]=896; a[4][10]=1600; a[5][10]=2496; a[6][10]=3600; a[7][10]=4896; a[8][10]=6400; 
a[1][11]=0; a[2][11]=484; a[3][11]=1064; a[4][11]=1936; a[5][11]=2984; a[6][11]=4356; a[7][11]=5872; a[8][11]=7744; 
a[1][12]=0; a[2][12]=576; a[3][12]=1248; a[4][12]=2304; a[5][12]=3520; a[6][12]=5184; a[7][12]=6960; a[8][12]=9216; 
a[1][13]=0; a[2][13]=676; a[3][13]=1512; a[4][13]=2704; a[5][13]=4224; a[6][13]=6084; a[7][13]=8280; a[8][13]=10816; 
a[1][14]=0; a[2][14]=784; a[3][14]=1746; a[4][14]=3136; a[5][14]=4870; a[6][14]=7056; a[7][14]=9564; a[8][14]=12544; 
a[1][15]=0; a[2][15]=900; a[3][15]=2016; a[4][15]=3600; a[5][15]=5616; a[6][15]=8100; a[7][15]=11016; a[8][15]=14400; 
a[1][16]=0; a[2][16]=1024; a[3][16]=2264; a[4][16]=4096; a[5][16]=6336; a[6][16]=9216; a[7][16]=12456; a[8][16]=16384; 
a[1][17]=0; a[2][17]=1156; a[3][17]=2600; a[4][17]=4624; a[5][17]=7224; a[6][17]=10404; a[7][17]=14160; a[8][17]=18496; 
a[1][18]=0; a[2][18]=1296; a[3][18]=2888; a[4][18]=5184; a[5][18]=8056; a[6][18]=11664; a[7][18]=15816; a[8][18]=20736; 
a[1][19]=0; a[2][19]=1444; a[3][19]=3218; a[4][19]=5776; a[5][19]=9008; a[6][19]=12996; a[7][19]=17666; a[8][19]=23104; 
a[1][20]=0; a[2][20]=1600; a[3][20]=3584; a[4][20]=6400; a[5][20]=9984; a[6][20]=14400; a[7][20]=19584; a[8][20]=25600; 
a[1][21]=0; a[2][21]=1764; a[3][21]=3912; a[4][21]=7056; a[5][21]=10942; a[6][21]=15876; a[7][21]=21500; a[8][21]=28224; 
a[1][22]=0; a[2][22]=1936; a[3][22]=4344; a[4][22]=7744; a[5][22]=12080; a[6][22]=17424; a[7][22]=23688; a[8][22]=30976; 
a[1][23]=0; a[2][23]=2116; a[3][23]=4712; a[4][23]=8464; a[5][23]=13144; a[6][23]=19044; a[7][23]=25808; a[8][23]=33856; 
a[1][24]=0; a[2][24]=2304; a[3][24]=5138; a[4][24]=9216; a[5][24]=14326; a[6][24]=20736; a[7][24]=28122; a[8][24]=36864; 
a[1][25]=0; a[2][25]=2500; a[3][25]=5612; a[4][25]=10000; a[5][25]=15624; a[6][25]=22500; a[7][25]=30624; a[8][25]=40000; 
a[1][26]=0; a[2][26]=2704; a[3][26]=6062; a[4][26]=10816; a[5][26]=16896; a[6][26]=24336; a[7][26]=33120; a[8][26]=43264; 
a[1][27]=0; a[2][27]=2916; a[3][27]=6536; a[4][27]=11664; a[5][27]=18184; a[6][27]=26244; a[7][27]=35664; a[8][27]=46656; 
a[1][28]=0; a[2][28]=3136; a[3][28]=6984; a[4][28]=12544; a[5][28]=19488; a[6][28]=28224; a[7][28]=38266; a[8][28]=50176; 
a[1][29]=0; a[2][29]=3364; a[3][29]=7520; a[4][29]=13456; a[5][29]=20968; a[6][29]=30276; a[7][29]=41200; a[8][29]=53824; 
a[1][30]=0; a[2][30]=3600; a[3][30]=8084; a[4][30]=14400; a[5][30]=22480; a[6][30]=32400; a[7][30]=44076; a[8][30]=57600; 

    int T; scanf("%d", &T);
    for(int i=1; i<=T; ++i){
        int n, r;
        scanf("%d%d", &n, &r);
        printf("%d\n", a[n][r]);
    }
    return 0;
}
A 打表

我還學了學模擬退火,但錯誤率很高,正確率大約1/3,只可作為參考。可能是我還不會模擬退火。

下面是我模擬退火的程式碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<vector>
#include<map>
using namespace std;

typedef pair<int,int> PII;

int n, r;
int ans[8];
vector<PII> V, V2;
map<int,int> M;

double calw(int a[]){
    double res=0;
    for(int i=0; i<n-1; ++i){
        for(int j=i+1; j<n; ++j){
            int tx=V[a[i]].first-V[a[j]].first, ty=V[a[i]].second-V[a[j]].second;
            res+=tx*tx+ty*ty;
        }
    }
    return res;
}

void gettmp(int a[], int b[], double T, int sz){
    int cnt=0;
    for(int i=0; i<n; ++i){
        do{
            a[i]=b[i]+(rand()*2-RAND_MAX)*T; while(a[i]<0) a[i]+=sz; a[i]%=sz;
        }while(0);
        M[a[i]]=1;
    }
}

void sa(double T, double down, double &answ, int sz){
    int cnt=0; double resw=answ;
    int res[8];
    for(int i=0; i<n; ++i) res[i]=ans[i];
    while(T>1e-5){
        int tmp[8]; M.clear();
        gettmp(tmp,res,T,sz);
        double tw=calw(tmp);
        if(tw>answ){
            for(int i=0; i<n; ++i) ans[i]=res[i]=tmp[i];
            answ=resw=tw;
        }else if(tw>resw || exp(tw-resw/T)*RAND_MAX>rand()){
            for(int i=0; i<n; ++i) res[i]=tmp[i];
            resw=tw;
        }
        T*=down;
    }
}

double SA(){
    V2.clear(); V.clear();
    for(int i=r-1, j=0; i>0; --i){
        while(i*i+(j+1)*(j+1)<=r*r) j++;
        V2.push_back(PII(j,i));
    }
    int sz=V2.size();
    V.push_back(PII(0,r));
    for(int i=0; i<sz; ++i) V.push_back(V2[i]);
    V.push_back(PII(r,0));
    for(int i=0; i<sz; ++i) V.push_back(PII(V2[i].first,-V2[i].second));
    V.push_back(PII(0,-r));
    for(int i=0; i<sz; ++i) V.push_back(PII(-V2[i].first,-V2[i].second));
    V.push_back(PII(-r,0));
    for(int i=0; i<sz; ++i) V.push_back(PII(-V2[i].first,V2[i].second));
    sz=V.size();
    double T=0.1, down=0.995, answ=calw(ans);
    for(int i=1; i<=10; ++i){
        sa(T,down,answ,sz);
    }
    return answ;
}

int main(){
    srand((unsigned)time(NULL));
//    freopen("A.txt","w",stdout);
    for(int i=1; i<=30; ++i){
        for(int j=1; j<=8; ++j){
            n=j; r=i;
            for(int i=0; i<n; ++i) ans[i]=0;
            double answ=SA();
            printf("\t%5.0lf", answ);
        }
        puts("");
    }
}
A 模擬退火

B. Mask Allocation

此題最大困難在於讀懂題意。

題意:給兩個數a,b,求一個數列,使得數列數之和等於a*b,可拼成a個b或b個a,且字典序最大。$n,m \le 10^4$

假設a<b,那麼數列中不能有題超過a的數字。a個a加上a*(b-a)個1一定是可行的。現在保住前面a個a,讓後面最大。將b-a看作t,那麼現在要求a*t的數列最大,這又回到了原題目,因此可以用迴圈的形式解決問題。

程式碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
 
int n, m;
vector<int> ans;
 
int main(){
    ios::sync_with_stdio(false);
    int T; cin>>T;
    while(T--){
        ans.clear();
        cin>>n>>m;
        while(n&&m){
            if(n>m) swap(n,m);
            for(int i=1; i<=n; ++i){
                ans.push_back(n);
            }
            m-=n;
        }
        int sz=ans.size();
        cout<<sz<<endl;
        for(int i=0; i<sz; ++i) cout<<ans[i]<<(i==sz-1?'\n':' ');
    }
}
B

C. A National Pandemic

題意:給一棵n個點的樹,初始點權都為0,後有m個操作,含3種類型:"1 x y"表示每個點u點權加上y-dis(x,u),其中dis(x,u)為x到u的距離;"2 x"表示將x點點權變為min(x點權,0);"3 x"表示詢問x點權。$1 \le n, m \le 5*10^4, y \le 10^4$

應該算是一道典型的樹上的題吧。對於1操作,y-dis(x,u)=y-dep(x)-dep(u)+2*dep(lca);這裡只有dep(lca)是x,u共同決定的,做法是將x到根的路徑上的所有點權加2,詢問時求點到根的點權和即可。對於2,另外設一個數組記錄即可。

程式碼如下:(其中大部分用的是樹鏈剖分模板,只看struct TtoC以外的部分即可)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

typedef long long LL;
const int N=50000+10;

int n, m;
LL val[N], a[N];
LL sumw, sumdep, cnt;

struct Graph{
    vector<int> G[N];
    
    void init(){
        for(int i=0; i<N; ++i){
            G[i].clear();
        }
    }
    
    void add(int u, int v){
        G[u].push_back(v);
        G[v].push_back(u);
    }
    
};

struct TtoC{//樹鏈剖分 TreeToChain
    Graph g;    //
    int r;        //根結點 
    int dfntot;
    int dfn[N], size[N], son[N], top[N], fa[N], dep[N], nfd[N];
    
    LL sum[N<<2], lazy[N<<2];
    
    void init(int r, Graph &g){
        //for(int i=0; i<N; ++i) this->g.G[i].clear();
        this->r=r;
        this->g=g;
        dfntot=0;
        memset(dep,0,sizeof(dep)); dep[r]=1;
        memset(son,0,sizeof(son));
        fa[r]=0;
        memset(lazy,0,sizeof(lazy));
    }
    
    void start(int r, Graph& g){
        init(r,g);
        dfs1(r);    //得到size, fa, dep, son 
        dfs2(r,r);    //得到dfn, top 
        build(1,1,n);    //線段樹的建立
    }
    
    void dfs1(int u){
        size[u]=1;
        int sz=g.G[u].size();
        for(int i=0; i<sz; ++i){
            int v=g.G[u][i];
            if(dep[v]) continue;
            dep[v]=dep[u]+1; fa[v]=u;
            dfs1(v);
            size[u]+=size[v];
            if(son[u]==0 || size[v]>size[son[u]]) son[u]=v;
        }
    }
    
    void dfs2(int u, int ffa){
        dfn[u]=++dfntot;
        nfd[dfntot]=u;
        top[u]=ffa;
        if(son[u]){
            dfs2(son[u],ffa);
        }
        int sz=g.G[u].size();
        for(int i=0; i<sz; ++i){
            int v=g.G[u][i];
            if(v==fa[u] || v==son[u]) continue;
            dfs2(v,v);
        }
    }
    
    void changeuv(int u, int v, int w){
        int tu=top[u], tv=top[v];
        while(tu!=tv){
            if(dep[tu]<dep[tv]){
                swap(u,v);
                swap(tu,tv);
            }
            change(1,1,n,dfn[tu],dfn[u],w);
            u=fa[tu];
            tu=top[u];
        }
        if(dep[u]<dep[v]) swap(u,v);
        change(1,1,n,dfn[v],dfn[u],w);
    }
    
    LL queryuv(int u, int v){
        LL res=0;
        int tu=top[u], tv=top[v];
        while(tu!=tv){
            if(dep[tu]<dep[tv]){
                swap(u,v);
                swap(tu,tv);
            }
            res+=query(1,1,n,dfn[tu],dfn[u]);
            u=fa[tu];
            tu=top[u];
        }
        if(dep[u]<dep[v]) swap(u,v);
        res+=query(1,1,n,dfn[v],dfn[u]);
        return res;
    }
    
    //以下為線段樹
    void build(int rt, int l, int r){
        if(l==r){
            sum[rt]=val[nfd[l]];
        }else{
            int mid=l+r>>1;
            build(rt<<1,l,mid);
            build(rt<<1|1,mid+1,r);
            sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        }
    }
    
    void change(int rt, int l, int r, int L, int R, int w){
        if(R<l || r<L) return;
        if(L<=l && r<=R){
            lazy[rt]+=w;
            return;
        }
        sum[rt]+=w*1ll*(R-L+1);
        int mid=l+r>>1;
        if(R<=mid) change(rt<<1,l,mid,L,R,w);
        else if(L>mid) change(rt<<1|1,mid+1,r,L,R,w);
        else { change(rt<<1,l,mid,L,mid,w); change(rt<<1|1,mid+1,r,mid+1,R,w); }
    }
    
    LL query(int rt, int l, int r, int L, int R){
        if(R<l || r<L) return 0;
        if(L<=l && r<=R) return sum[rt]+lazy[rt]*(r-l+1);
        int mid=l+r>>1;
        LL res=0;
        if(R<=mid) res=query(rt<<1,l,mid,L,R);
        else if(L>mid) res=query(rt<<1|1,mid+1,r,L,R);
        else res=query(rt<<1,l,mid,L,mid)+query(rt<<1|1,mid+1,r,mid+1,R);
        return res+lazy[rt]*(R-L+1);
    }
};

Graph g;
TtoC ttc;

LL query(int u){
    return sumw-sumdep-cnt*ttc.dep[u]+ttc.queryuv(1,u)+a[u];
}

int main(){
    int T; scanf("%d", &T);
    while(T--){
        g.init();
        memset(val,0,sizeof(val));
        memset(a,0,sizeof(a));
        sumw=sumdep=cnt=0;
        
        scanf("%d%d", &n, &m);
        for(int i=1, u, v; i<n; ++i){
            scanf("%d%d", &u, &v);
            g.add(u,v);
        }
        
        ttc.start(1,g);
        for(int i=1; i<=m; ++i){
            int opt, x; LL y;
            scanf("%d", &opt);
            switch(opt){
                case 1:
                    scanf("%d%lld", &x, &y);
                    ttc.changeuv(1,x,2);
                    sumw+=y;
                    sumdep+=ttc.dep[x];
                    cnt++;
                    break;
                case 2:
                    scanf("%d", &x);
                    y=query(x);
                    if(y>0) a[x]-=y;
                    break;
                case 3:
                    scanf("%d", &x);
                    printf("%lld\n", query(x));
                    break;
            }
        }
    }
    return 0;
}
C

樹上的有關知識該複習了,可以看看 qtree

D. ac

沒看,應該是水題

H. Dividing

題意:定義滿足以下條件為the Legend Tuple:1.(1,k)是;2.如果(a,b)是,則(a+b,b)也是;3.若(a,b)是,則(a*b,b)也是。現求所有滿足$1 \le n \le N, 1\le k \le K$的(n,k)個數。$1 \le N, K \le 10^{12}$

對於固定的k,(n,k)是the legend tuple的充要條件是n%k=1或n%k=0。因此當k=1或2時,所有n都滿足;當k>2時,n個數是n/k+(n-1)/k+1。

對於$\sum_{i=1}^k \frac{n}{i} $每項下取整是有方法的,時間複雜度O(logn)。

程式碼見下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const LL P=1e9+7;
LL n, k;

// n/1 + n/2 + ... + n/k向下取整 
LL cal(LL n, LL k){
    if(!n||!k) return 0;
    LL res=0, i, j;
    for(i=1; i<=k; i=j+1){
        j=n/(n/i);
        res=(res+(n/i)%P*(j-i+1)%P)%P;
    }
    return (res-n/(i-1)%P*(i-k-1)%P+P)%P;
}

//向上取整 
LL cal22(LL n, LL k){
    if(n==k) return (cal(n-1,k-1)+k)%P;
    return (cal(n-1,k)+k)%P;
}

LL shang(LL a, LL b){
    return (a+b-1)/b;
}
int main(){
//    freopen("data.txt","r",stdin);
//    freopen("my.txt","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n>>k;
    if(k<3){
        cout<<n*k%P<<endl;
        return 0;
    }
    LL ans;
    if(n>=k) ans=cal(n,k)+cal22(n,k)-n/2%P-shang(n,2)%P+P+P, ans%=P;
    else ans=cal(n,n)+cal22(n,n)-n/2%P-shang(n,2)%P+k-n+P+P, ans%=P;
    cout<<ans<<endl;
}
H

題解用了另一種方法,我沒看懂,就不寫在這裡了。

I. Valuable Forests

題意:定義一個森林的值為森林中所有點的度數的平方和。T次詢問,每次求所有含n個帶標號的點的森林的值之和,結果對P取模。$1 \le T \le 5000, 1 \le n \le 5000, 1 \le P \le 2^{30} 且為質數$

這題的主要攻克點:

1.Cayley n頂點樹數定理:

n個點的帶標號樹個數為$n^{n-2}$。

證明方法:將一棵樹和一個數列$\{a_i,a_2,...a_{n-2}\}$對應起來,其中$1 \le a_i \le n$,因此共$n^{n-2}$個。同時,每個數$i$出現$d_i-1$次,$d_i$是度數。

2. 遞推的方式。

具體實現方式一篇題解寫的很好,我再寫也不過是複述而已:https://blog.nowcoder.net/n/026e1c74bc9949e2b57584ac83074404

下面是我的程式碼:

//code by cyh
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

typedef long long LL;
const int N=5000+10;

LL p;
LL fn[N], fv[N], tn[N], tv[N], tmp[N];
LL fa[N], fb[N], CC[N][N];

LL Pow(LL x, LL n, LL P){
    if(n==0) return 1;
    LL tmp=Pow(x,n/2,P);
    if(n&1) return tmp*tmp%P*x%P;
    return tmp*tmp%P;
}

void init(int P){
    LL x, y;
    fa[0]=1; fn[0]=1; tv[1]=0; tn[0]=tn[1]=1;
    CC[0][0]=1;
    for(int i=1; i<N; ++i){
        CC[i][0]=1;
        for(int j=1; j<=i; ++j){
            CC[i][j]=(CC[i-1][j]+CC[i-1][j-1])%P;
        }
    }
    for(int i=2; i<N; ++i) tn[i]=Pow(i,i-2,P);
    for(int n=1; n<N; ++n){
        for(int i=0; i<n; ++i) fn[n]=(fn[n]+CC[n-1][i]*fn[n-1-i]%P*tn[i+1]%P)%P;
    }
    for(int n=2; n<N; ++n){
        tmp[0]=1;
        for(int i=1; i<=n; ++i) tmp[i]=tmp[i-1]*(n-1)%P;
        for(int i=0; i<n; ++i) tv[n]=(tv[n]+CC[n-2][i]*(i+1)%P*(i+1)%P*tmp[n-2-i]%P)%P;
        tv[n]=tv[n]*n%P;
    }
    for(int n=1; n<N; ++n){
        for(int i=0; i<n; ++i) fv[n]=(fv[n]+CC[n-1][i]*(fv[n-i-1]*tn[i+1]%P+fn[n-i-1]*tv[i+1]%P)%P)%P;
    }

}

int main(){
//    freopen("data.txt","r",stdin);
//    freopen("my.txt","w",stdout);
    int T; scanf("%d%lld", &T, &p);
    init(p);
    for(int i=1, x; i<=T; ++i){
        scanf("%d", &x);
        printf("%lld\n", fv[x]);
    }
    return 0;
}

I
I