2020.5.2-西工大校賽


A.張經理的員工

鏈接:https://ac.nowcoder.com/acm/contest/5403/A
來源:牛客網

張經理的公司的辦公室長達100000米,從最左端開始每間隔1米都有一個工位(從第1米開始有工位),位於第i米的工位稱為i號工位,且這些工位都在一條水平線上。他有n個員工,每個員工分別位於xi號工位上(不同員工可能位於同一個工位)。

現在張經理想把員工聚集在某兩個工位上,他有q套方案(每套方案包含兩個工位號,兩個工位號可能相同),他想知道對於每套方案,所有員工都到達兩個工位中的某一個所需走的最短路徑之和是多少。

輸入描述:

第一行輸入兩個正整數n, q

第二行輸入n個正整數xi,分別代表第i個員工的工位

之后q行每行輸入兩個整數a,b,代表該套方案要求的兩個集合位置

(1<=n,q,xi,a,b<=105)(1<=n,q,xi,a,b<=10^5)1<=n,q,xi,a,b<=105)

輸出描述:

對於每套方案,輸出一個整數代表答案,每個答案獨占一行。
示例1

輸入

復制

輸出

復制
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 100005;
int a[maxn] , b[maxn];
ll pre[maxn] , fpre[maxn];
ll cpre[maxn] , cfpre[maxn];
int main()
{
    int n,q;
    cin>>n>>q;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[a[i]]++;
    }
    ll sum = 0,sum2 = 0;
    for(int i=1;i<=100000;i++){
        if(b[i]){
            sum += 1ll*i*b[i];
            sum2 += 1ll*b[i];
        }
        pre[i] = sum;
        cpre[i] = sum2;
    }
    sum = 0,sum2 = 0;
    for(int i=100000;i>=1;i--){
if(b[i]){
            sum += 1ll*i*b[i];
            sum2 += 1ll*b[i];
        }
        fpre[i] = sum;
        cfpre[i] = sum2;
    }
    while(q--){
        int l,r;
        ll ans = 0;
        scanf("%d %d",&l,&r);
        if(l > r)
            swap(l , r);
        ll x = 1ll*cpre[l]*l - 1ll*pre[l];
        ll y = 1ll*fpre[r] - 1ll*cfpre[r]*r;
        ll z = 0 , w = 0;
        if(r - l > 1){
            int x = r - l;
            int l2 = l + x/2;
            z = pre[l2] - pre[l] - (cpre[l2] - cpre[l])*l;
            int r2 = l2;
            w = r*(cpre[r-1] -  cpre[r2]) - (pre[r-1] - pre[r2]);
        }
        cout<<x + y + z + w<<endl;
    }
     return 0;
}

B.隨機序列

鏈接:https://ac.nowcoder.com/acm/contest/5403/B
來源:牛客網

國中生Chino總是做不完數學作業,Cocoa想來幫忙,但作業太多了,怎么也做不完。

Chino的數學作業由 T(1≤T≤100)T(1\leq T\leq 100)T(1T100)張試卷組成,每張試卷上有n(1≤n≤103)n(1\leq n\leq 10^3)n(1n103)個數a1..n(1≤a≤5000)a_{1..n}(1\leq a\leq 5000)a1..n(1a5000),Chino需要算出這些數的極差和方差。極差是一個整數,方差是一個浮點數,要求保留到小數點后3位。

雖然題目很簡單,但計算量對於Chino來說實在太大啦!你能幫一幫她嗎?

P.S.:一個數列的極差是指數列中最大的數減去最小的數,方差是指算出數列中每個數與數列平均值之差的平方后,對其求和,再除以數列元素個數得到的結果。

輸入描述:

輸入的第一行有一個數T,表示試卷的數量;接下來的每2行,第一行有一個數n,表示當前試卷上數字的個數;第二行有n個數字 aia_iai,表示這張試卷上的每一個數。

輸出描述:

對每張試卷,輸出一行兩個數,分別表示這些數字的極差和方差,中間用空格分開。其中極差是整數,方差是保留到小數點后3位的浮點數。
示例1

輸入

2
5
5 4 3 2 1
7
333 494 655 991 101 591 941

輸出

4 2.000
890 86075.959
#include<stdio.h>
#include<math.h>
int main()
{
    int t,n,s[10000];
    int i,j;
    int jc;
   // float aver,num=0,sum=0;
    double m;
    scanf("%d",&t);
    while(t--)
    {
        double aver,num=0,sum=0;
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%d",&s[i]);
            sum+=s[i];
        }
        int min=10000,max=-1;
        for(i=0;i<n;i++)
        {
            if(s[i]<=min)min=s[i];
            if(s[i]>=max)max=s[i];
        }
        jc=max-min;
        aver=sum/n;
        for(i=0;i<n;i++)
        {
            m=(s[i]-aver)*(s[i]-aver);
            num+=m;
        }
        //printf("%.4lf\n",num);
        num/=n;
        printf("%d %.3lf\n",jc,num);
    }
}

C.王國

鏈接:https://ac.nowcoder.com/acm/contest/5403/C
來源:牛客網

這個世界上有 n(n≤105)n(n\le 10^5)n(n105)個王國,有n-1條道路,任意兩個王國相互可達. 每個王國都有屬於某個勢力,王國i屬於勢力ai(ai≤n)a_i(a_i\le n)ai(ain) ,勢力相同的王國想要相互聯絡.王國a與王國b的聯絡難度為x2x^2x2(x為a到b簡單路徑上邊的數量)

輸出最大的聯絡難度.

輸入描述:

第一行為正數n,表示王國數量

第二行為n個正整數,a1,a2...ana_1,a_2...a_na1,a2...an ,aia_iai 表示王國i所屬的勢力.

接下來的n-1行,每行2個正整數u,v. 表示王國u與王國v有道路相連.

輸出描述:

輸出最大聯絡難度
示例1

輸入

7
1 1 2 3 3 3 1
1 2
1 3
2 4
2 5
3 6
1 7

輸出

16

說明

王國4與王國6聯系的難度為16
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3;
const int N=2e5+10;
 
int dfn[N],numdfn;
int n,max_deep;
int a[N];
/*
    lca部分
*/
struct LCA
{
    int head[N],dep[N],fa[N][22],cnt;
    struct edge
    {
        int v,w,next;
    }e[N*2];
    void add(int u,int v,int w)
    {
        e[++cnt]={v,w,head[u]};head[u]=cnt;
        e[++cnt]={u,w,head[v]};head[v]=cnt;
    }
 
    void dfs(int u,int d,int f)
    { dep[u]=d;fa[u][0]=f;
        dfn[u]=++numdfn;
        max_deep=max(max_deep,d);
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].v;
            if(v==f) continue;
            dfs(v,d+1,u);
        }
    }
    void init()
    {
        dfs(1,0,1);
        for(int k=1;k<=20;++k)
        for(int i=1;i<=n;++i)
        fa[i][k]=fa[fa[i][k-1]][k-1];
    }
 
    int lca(int u,int v)
    {
        if(dep[u]<dep[v]) swap(u,v);
        for(int k=20;k>=0;--k)
            if(dep[fa[u][k]]>=dep[v]) u=fa[u][k];
 if(u==v) return v;
        for(int k=20;k>=0;--k)
            if(fa[u][k]!=fa[v][k]) u=fa[u][k],v=fa[v][k];
        return fa[u][0];
    }
    int findlen(int  u,int v)
    {
        return dep[u]+dep[v]-2*dep[lca(u,v)];
    }
}L;
/*
    虛樹部分
*/
vector<int>has[N];
vector<pair<int,int> >G[N];
 
int st[N],top,cnt;
int numid;
 
bool cmp(int x,int y)
{
    return dfn[x]<dfn[y];
}
 
void ins(int id,int x)//插入虛樹新點
{
    if(top==1){st[++top]=x;return ;}

int fa=L.lca(x,st[top]);
    if(fa==st[top]){//就在該鏈的下方
        st[++top]=x;return ;
    }
 
 
    while(top>1&&dfn[st[top-1]]>=dfn[fa]){
        int p1=st[top],p2=st[top-1];//該相鄰兩節點相連
        //建虛樹圖
        int w=L.findlen(p1,p2);
        G[p1].emplace_back(make_pair(p2,w));
        G[p2].emplace_back(make_pair(p1,w));
        --top;
    }
    if(st[top]!=fa){
        int p1=st[top],p2=fa;
        int w=L.findlen(p1,p2);
        G[p1].emplace_back(make_pair(p2,w));
        G[p2].emplace_back(make_pair(p1,w));
        st[top]=fa;
    }
    st[++top]=x;
}
void build(int id,vector<int>& has)
{
    sort(has.begin(),has.end());
    has.erase(unique(has.begin(),has.end()),has.end());
 sort(has.begin(),has.end(),cmp);
    st[top=1]=1;
    //top=0;
    for(int v:has) ins(id,v);
 
    //printf("top:%d\n",top);
 
    while(top>1)
    {
        int p1=st[top],p2=st[top-1];
        int w=L.findlen(p1,p2);
        G[p1].emplace_back(make_pair(p2,w));
        G[p2].emplace_back(make_pair(p1,w));
        --top;
    }
}
int mx,mi;
int tar;
void dfs1(int u,int fa,int dep,int val,int ty)
{
    //printf("u:%d fa:%d\n",u,fa);
    if(a[u]==ty&&dep>mi){
        mi=dep,tar=u;
    }
    for(auto now:G[u]){
        if(now.first==fa) continue;
if(now.first==u) continue;//1可能跟自己又連了一條邊
        //printf("fa:%d u:%d v:%d w:%d\n",fa,u,now.first,now.second);
 
        dfs1(now.first,u,dep+now.second,val,ty);
    }
    if(val==1) G[u].clear();
}
 
int bfs(int rt,int ty)
{
    mi=-1;
    dfs1(rt,-1,0,0,ty);
    mi=-1;
//    puts("");
//    printf("tar:%d\n",tar);
//    puts("");
    dfs1(tar,-1,0,1,ty);
//    printf("ty:%d mi:%d\n",ty,mi);
//    puts("");
//    puts("");
    return mi;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) {
        scanf("%d",&a[i]);
 has[a[i]].push_back(i);
        mx=max(mx,a[i]);
    }
 
    for(int i=1;i<n;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        L.add(u,v,1);
    }
    L.init();
 
    int ans=0;
 
    for(int i=1;i<=mx;++i){
        if(has[i].size()==0) continue;
 
        build(i,has[i]);
        ans=max(ans,bfs(has[i][0],i));
    }
    printf("%lld\n",1ll*ans*ans);
}

D卡拉茲函數

鏈接:https://ac.nowcoder.com/acm/contest/5403/D
來源:牛客網

卡拉茲函數是怎么回事呢?卡拉茲相信大家都很熟悉,但是卡拉茲函數是怎么回事呢,下面就讓小編帶大家一起了解吧。  
卡拉茲函數,其實就是當n是奇數時,輸出3*n+1,當n是偶數時,輸出n/2,大家可能會很驚訝卡拉茲怎么會是函數呢?但事實就是這樣,小編也感到非常驚訝。  
這就是關於卡拉茲函數的事情了,大家有什么想法呢,歡迎在評論區告訴小編一起討論哦!

 

輸入描述:

一個不超過10

5

的正整數n

輸出描述:

一行一個整數k。當n是奇數時,k=3*n+1,當n是偶數時,k=n/2。
示例1

輸入

1

輸出

4

說明

 
示例2

輸入

2

輸出

1
#include<stdio.h>
#include<math.h>
int main()
{
    int n;
    long long k;
    while(scanf("%d",&n)!=EOF)
    {
        if(n%2!=0)
        {
            k=3*n+1;
            printf("%lld\n",k);
        }
        else {
            k=n/2;
            printf("%lld\n",k);
        }
    }
}

E張經理的字符串

鏈接:https://ac.nowcoder.com/acm/contest/5403/E
來源:牛客網

張經理有n個字符串和一個轉化表,轉化表里記錄了m個字符串。

張經理對其擁有的字符串可以進行3種操作:

1、在一個字符串末尾刪除一個字符

2、在一個字符串末尾添加一個任意字符

3、若有一字符串s等於轉化表中記錄的某一字符串,則可將s轉化為轉化表中記錄的任一字符串

張經理的舍友要送給他一個字符串p,但只告訴張經理p等於他擁有的某一字符串的某一非空前綴。

張經理想知道當p分別等於其擁有的每個串的每個非空前綴時,將其擁有的串和p轉化為相同字符串(可以為空)需要的最少操作數。

輸入描述:

第一行輸入兩個整數n,m(1<=n, m<=40)

第2到n+1行輸入張經理擁有的n個字符串

第n+2行到n+m+1行輸入轉化表中的m個字符串

每個字符串都由小寫英文字母組成,且長度不超過400

輸出描述:

分別輸出當p等於張經理擁有的每個串的每個非空前綴時(字符串按輸入順序,前綴按從短到長),張經理將其所有的串和p轉化為相同字符串(可以為空)所需的最少操作數,數字間用空格間隔。
示例1

輸入

2 2
abcd
ab
abcd
ab

輸出

2 1 2 1 2 1

說明

 
示例2

輸入

4 2
a
b
b
b
npu
acm

輸出

4 2 2 2
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define maxn 100100
using namespace std;

int n, m, vis[maxn], dis[maxn], sum[maxn];
int lenA[45], lenB[45], tree[maxn][27], tot=1, posA[45][405], posB[45][405];
vector<int> edge[maxn];
string A[45], B[45];

void insert(string s, int pos[][405], int p)
{
    int len=s.size(), rt=1, id;
    for (int i=0; i<len; i++)
    {
        id=s[i]-'a';
        if (!tree[rt][id])
        {
            tree[rt][id]=++tot;
            edge[rt].push_back(tot);
            edge[tot].push_back(rt);
        }
        rt=tree[rt][id];
        pos[p][i]=rt;
    }
}

void dijkstra(int s, int f)
{
    priority_queue<pair<int, int> > pq;
    if (f==0)
    {
        memset(dis, 127, sizeof(dis));
        dis[s]=0;
        pq.push(make_pair(0, s));
    }
    else
    {
        for (int i=1; i<=tot; i++)
        {
            dis[i]=sum[i];
            pq.push(make_pair(-dis[i], i));
        }
    }
    while (!pq.empty())
    {
        auto temp=pq.top(); pq.pop();
        temp.first*=-1;
        if (dis[temp.second]!=temp.first) continue;
        for (auto i: edge[temp.second])
        {
            if (dis[i] > dis[temp.second]+1)
            {
                dis[i]=dis[temp.second]+1;
                pq.push(make_pair(-dis[i], i));
            }
        }
    }
}

int main()
{
    cin>>n>>m;
    for (int i=1; i<=n; i++)
    {
        cin>>A[i];
        lenA[i]=A[i].size();
    }
    for (int i=1; i<=m; i++)
    {
        cin>>B[i];
        lenB[i]=B[i].size();
    }
    for (int i=1; i<=n; i++)
        insert(A[i], posA, i);
    for (int i=1; i<=m; i++)
        insert(B[i], posB, i);
    for (int i=1; i<=m; i++)
        for (int j=i+1; j<=m; j++)
        {
            edge[posB[i][lenB[i]-1]].push_back(posB[j][lenB[j]-1]);
            edge[posB[j][lenB[j]-1]].push_back(posB[i][lenB[i]-1]);
        }
    for (int i=1; i<=n; i++)
    {
        dijkstra(posA[i][lenA[i]-1], 0);
        for (int j=1; j<=tot; j++)
            sum[j]+=dis[j];
    }
    dijkstra(0, 1);
    for (int i=1; i<=n; i++)
    {
        for (int j=0; j<lenA[i]; j++)
            cout<<dis[posA[i][j]]<<" ";
    }
    return 0;
}

F四等分的角度

鏈接:https://ac.nowcoder.com/acm/contest/5403/F
來源:牛客網

輸入點A、O、B的坐標,找任意三個點 K1K_1K1K2K_2K2K3K_3K3,使得射線OK1OK_1OK1OK2OK_2OK2OK3OK_3OK3把∠AOB四等分(∠AOB<180°)。

輸入描述:

三行,每行兩個整數 xix_ixiyiy_iyi,依次表示A、O、B的坐標。數據保證A、O、B三點不共線,且O點坐標絕對值均不超過10910^9109、向量OA\boldsymbol{OA}OA、OB\boldsymbol{OB}OB的模均在[1,105)[1,10^5)[1,105)范圍內。

輸出描述:

三行,每行兩個浮點數 xKix_{K_i}xKiyKiy_{K_i}yKi,表示點KiK_iKi的坐標。
注意KiK_iKi輸出的順序:設PiP_iPi為線段AB與射線OKiOK_iOKi的交點,要求點A、P1P_1P1P2P_2P2P3P_3P3、B在線段AB上依次排列。(不要求KiK_iKi必須在三角形外部)

精度要求:如果對每個輸出的答案KiK_iKi,向量OKi\boldsymbol{OK_i}OKi的極角弧度與標准答案的向量OKistd\boldsymbol{OK_{i_{std}}}OKistd的極角弧度相差不超過2π3600\displaystyle \frac{2\pi}{3600}36002π,則你的答案視為正確。

下圖的點K1K_1K1K2K_2K2K3K_3K3是給定A、O、B的一組合法解的例子:
 
示例1

輸入

-2 4
0 0
10 3

輸出

-0.52807805 18.92205855
5.33095299 12.33809402
14.14096896 12.58396453
#include <bits/stdc++.h>
using namespace std;
struct node
{
    double x,y;
}a,o,b;
double dis(node p,node q)
{
    return sqrt((p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y));
}
double get_angle(node aa,node oo,node bb)
{
    double ao=dis(aa,oo),ab=dis(aa,bb),bo=dis(bb,oo);
    return acos((ao*ao+bo*bo-ab*ab)/(2*ao*bo));
}
node solve(node aa,double angle)
{
    double x=cos(angle)*aa.x-sin(angle)*aa.y;
    double y=sin(angle)*aa.x+cos(angle)*aa.y;
    return {x,y};
}
int main()
{
    scanf("%lf %lf",&a.x,&a.y);
    scanf("%lf %lf",&o.x,&o.y);
    scanf("%lf %lf",&b.x,&b.y);
    node tmp=o;
    a.x-=o.x,a.y-=o.y,b.x-=o.x,b.y-=o.y;//將o移到原點
    o.x-=o.x,o.y-=o.y;
    double angle=get_angle(a,o,b);
    bool opt;
    node ans;
    if((a.y>=0&&b.y>=0)||(a.y<=0&&b.y<=0))//判斷以哪條邊逆時針旋轉
    {
        if(a.y>=0&&b.y>=0)
        {
            if(get_angle(a,o,{1,0})>get_angle(b,o,{1,0}))
            ans=b,opt=1;
            else
            ans=a,opt=0;
        }
        else
        {
            if(get_angle(a,o,{1,0})<get_angle(b,o,{1,0}))
            ans=b,opt=1;
            else
            ans=a,opt=0;
        }
    }
    else
    {
        if(a.y>0)
        {
            if(get_angle(b,o,{1,0})>get_angle({-a.x,-a.y},o,{1,0}))
            ans=a,opt=0;
            else
            ans=b,opt=1;
        }
        else if(b.y>0)
        {
            if(get_angle(a,o,{1,0})>get_angle({-b.x,-b.y},o,{1,0}))
            ans=b,opt=1;
            else
            ans=a,opt=0;
        }
    }
    node res1,res2,res3;
    res1=solve(ans,angle*3/4);
    res2=solve(ans,angle/2);
    res3=solve(ans,angle/4);
    if(opt)
    {
        printf("%lf %lf\n",res1.x+tmp.x,res1.y+tmp.y);//答案要把o點移回去哦 >_<
        printf("%lf %lf\n",res2.x+tmp.x,res2.y+tmp.y);
        printf("%lf %lf\n",res3.x+tmp.x,res3.y+tmp.y);
    }
    else
    {
        printf("%lf %lf\n",res3.x+tmp.x,res3.y+tmp.y);
        printf("%lf %lf\n",res2.x+tmp.x,res2.y+tmp.y);
        printf("%lf %lf\n",res1.x+tmp.x,res1.y+tmp.y);
    }
    return 0;
}

 

G智乃與無意義的題目

鏈接:https://ac.nowcoder.com/acm/contest/5403/G
來源:牛客網

Chino的數論很差,因此Cocoa非常擔心。這一天,Cocoa給了Chino一道非常meaningless的數論題:

n(1≤n≤105)n(1\leq n\leq 10^5)n(1n105)個數a1⋯n(1≤ai≤10)a_{1\cdots n}(1\leq a_i\leq 10)a1n(1ai10),以及q(1≤q≤105)q(1\leq q\leq 10^5)q(1q105)個操作,操作分為兩種:

  • 1 p v,令ap(1≤p≤n)=v(1≤v≤10)a_{p}(1\leq p\leq n)=v(1\leq v\leq 10)ap(1pn)=v(1v10)

  • 2 l r,查詢f(al×al+1×⋯×ar)(1≤l≤r≤n)f(a_{l}\times a_{l+1}\times \cdots \times a_{r})(1\leq l\leq r\leq n)f(al×al+1××ar)(1lrn),其中f(n)=∑i∣n1f(n)=\sum_{i|n}1f(n)=in1(n的因數個數)

對於每個2 l r,你需要給出答案。由於答案可能會很大,因此你只需要輸出 mod 998244353\bmod{998244353}mod998244353后的值即可。

雖然題目非常meaningless,但是對於Chino來說還是太難啦!你能幫一幫她嗎?

輸入描述:

輸入的第一行有兩個數n,m,表示數列的長度和詢問的個數;接下來一行有n個數aia_iai;接下來m行每行包含了一個1 p v或者2 l r.

輸出描述:

對於每個2 l r,你需要輸出答案,每個答案獨占一行。
示例1

輸入

5 3
1 2 3 4 5
2 1 5
1 1 2
2 1 5

輸出

16
20

備注:

Hint
120=1×120=2×60=3×40=4×30=5×24=6×20=8×15=10×12120=1\times 120=2\times 60=3\times 40=4\times 30=5\times 24=6\times 20=8\times 15=10\times 12120=1×120=2×60=3×40=4×30=5×24=6×20=8×15=10×12.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = (int)1e9 + 7;
const int inf = 0x3f3f3f3f; //初始化無窮大
int a[100005];
int main()
{
 ios::sync_with_stdio(false);
 cin.tie(0);
 int n, num;
 cin >> n >> num;
 for (int i = 1; i <= n; ++i)
 {
  cin >> a[i];
 }
 while (num)
 {
  int b, c, d;
  cin >> b >> c >> d;
  if (b == 1)
  {
   a[c] = d;
  }
  if (b == 2)
  {
   ll ans = 1;
   for (int i = c; i <= d; ++i)
    ans *= a[i];
   ll count = 0;
   ll cc = sqrt(ans);
   for (ll i = 1; i < cc; ++i)
   {
    if (ans % i == 0)
    {
     count += 2;
     count %= 998244353;
    }
   }
   if (cc * cc == ans)count += 1;
   if (cc * cc < ans && (ans % cc == 0))
   {
    count += 2;
   }
   cout << count % 998244353 << endl;
  }
  --num;
 }
 return 0;
}

 

I小朋友你是否有很多問號

鏈接:https://ac.nowcoder.com/acm/contest/5403/I
來源:牛客網

”這老師講的也太簡單了吧,聽得我想睡覺“,小明對着正在放着數學網課的電腦屏幕自顧自地大笑道。

說完這句后,QQ框突然瘋狂地抖動起來,小明打開一看,全是群消息:

小紅:小明,你忘關麥了!

小剛:這小伙子勇啊。

大劉:沒救了,厚葬吧。

“卧槽”,小明大吼道,突然又意識到什么,趕緊捂住嘴巴然后回到網課界面把麥克風關掉。
”小明啊“,數學老師停下了講課,幽幽地說,”看來你學的挺好,那么來做一下這道題吧,寫不出的話返校后我的數學課你就倒立着聽。“

小明:?????
題目描述

我們定義公質數:若存在三個正整數a,b,ca,b,ca,b,c且滿足aaa與ccc互質且bbb與ccc互質,那么我們就稱ccc是aaa,bbb的二元公質數。同理,如果ccc同時與kkk個數互質,那么稱ccc是這kkk個數的kkk元公質數。現在給你nnn個數,求出其中任意mmm個數的所有mmm元公質數(要求公質數也在這nnn個數中)的和。(詳見樣例)


輸入描述:

第一行輸入一個n,m(3<=n<=100000, 2 <= m <=n)

第二行輸入n個數字ai(2<=ai<=100000)a_i(2<=a_i<=100000)ai(2<=ai<=100000),中間以空格隔開。

輸出描述:

如題所述,最后答案對998244353取模
示例1

輸入

4 2

3 3 5 5

輸出

復制
16

說明

(3,3)的二元公質數有5,5;
(3,5)沒有二元公質數;
(5,5)的公質數有:3,3;
 因此答案為:5+5+3+3=16
示例2

輸入

6 2

2 3 4 5 20 30

輸出

39

說明

(2,3)的二元公質數有5, 
同理(2, 4):3, 5; 
(2, 5):3; 
(2, 20):3 
(2, 30): 無; 
(3, 4): 5; 
(3, 5): 2, 4; 
(3, 20):無; 
(3, 30): 無; 
(4, 5):3; 
(4, 20): 3; 
(4, 30):無 
(5, 20): 3; 
(5, 30):無; 
(20, 30):無
因此ans = 5 + 3 + 5 + 3 + 3 + 5 + 2 + 4 + 3 + 3 +3 = 39
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int MAX_N=101000;
const long long MOD=998244353;
vector<int>v[MAX_N];
int prime[1010],tot=0;
bool vis[1010];
void init(int x){//求質數
    int i,j;
    for(i=2;i<=x;i++){
        if(vis[i])
        continue;
        prime[++tot]=i;
        for(j=i+i;j<=x;j+=i)
        vis[j]=true;
    }
}
int p[MAX_N][7],cnt;
int tt[MAX_N];
int num[MAX_N];
long long F[MAX_N];
long long b[MAX_N];
long long pow_mod(long long a,long long n,long long m){
    long long ans=1;
    while(n){
        if(n&1){
            ans=(ans*a)%m;
        }
        a=(a*a)%m;
        n>>=1;
    }
    return ans;
}
long long C(int n,int m){//求組合數,提前預處理出階乘數組F
    return F[n]*pow_mod(F[m]*F[n-m]%MOD,MOD-2,MOD)%MOD;
}
int main(void){
    int n,m,i,j,k,x;
    init(1000);
    scanf("%d%d",&n,&m);
    F[0]=1;
    for(i=1;i<=n;i++)
    F[i]=i*F[i-1]%MOD;
    for(i=1;i<=n;i++){
        scanf("%d",&x);
        b[i]=x;
        cnt=0;
        for(j=1;j<=tot;j++){
            if(x==1)
            break;
            if(x%prime[j]==0){
                while(x%prime[j]==0)
                x/=prime[j];
                p[i][cnt++]=prime[j];
            }
        }
        if(x!=1)
        p[i][cnt++]=x;
        for(j=0;j<(1<<cnt);j++){//用每個數分解的質數進行組合計算出num數組
            int s=1;
            for(k=0;k<cnt;k++){
                if(j&(1<<k)){
                    s*=p[i][k];
                }
            }
            num[s]++;
        }
        tt[i]=cnt;
    }
    long long ans=0;
    for(i=1;i<=n;i++){
        cnt=tt[i];
        int res=0;
        for(j=1;j<(1<<cnt);j++){
            int s=1,sum=0;
            for(k=0;k<cnt;k++){
                if(j&(1<<k)){
                    s*=p[i][k];
                    sum++;
                }
            }//通過計算sum進行奇加偶減
            if(sum%2==1)
            res+=num[s];
            else
            res-=num[s];
        }
        res=n-res;
        if(res>=m)
        ans=(ans+b[i]*C(res,m)%MOD)%MOD;
    }
    printf("%lld\n",ans);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM