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