QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#742776#9619. 乘积,欧拉函数,求和Aicu123TL 7ms4432kbC++204.4kb2024-11-13 17:17:472024-11-13 17:17:53

Judging History

你现在查看的是最新测评结果

  • [2024-11-13 17:17:53]
  • 评测
  • 测评结果:TL
  • 用时:7ms
  • 内存:4432kb
  • [2024-11-13 17:17:47]
  • 提交

answer

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define pii pair<int,int>
#define fi first
#define se second
//cout<<setiosflags(ios::fixed)<<setprecision(K);
const int dx[4]={1,-1,0,0};
const int dy[4]={0,0,1,-1};
const double eps=1e-9; 
const double PI=acos(-1.0);
const int inf=1e9+7;
const int mod=998244353;

const int m=16;
const int prime[m]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
// assume -P <= x < 2P
const int P=mod;
int norm(int x) {
    if (x < 0) x += P;
    if (x >= P) x -= P;
    return x;
}
template<class T>
T power(T a, ll b) {
    T res = 1;
    for (; b; b /= 2, a *= a) {
        if (b % 2) {res *= a;}
    }
    return res;
}
struct Z {
    int x;
    Z(int x = 0) : x(norm(x)) {}
    Z(ll x) : x(norm(x % P)) {}
    int val() const {
        return x;
    }
    Z operator-() const {
        return Z(norm(P - x));
    }
    Z inv() const {
        assert(x != 0);
        return power(*this, P - 2);
    }
    Z &operator*=(const Z &rhs) {
        x = (ll)x * rhs.x % P;
        return *this;
    }
    Z &operator+=(const Z &rhs) {
        x = norm(x + rhs.x);
        return *this;
    }
    Z &operator-=(const Z &rhs) {
        x = norm(x - rhs.x);
        return *this;
    }
    Z &operator/=(const Z &rhs) {
        return *this *= rhs.inv();
    }
    friend Z operator*(const Z &lhs, const Z &rhs) {
        Z res = lhs;res *= rhs;
        return res;
    }
    friend Z operator+(const Z &lhs, const Z &rhs) {
        Z res = lhs;res += rhs;
        return res;
    }
    friend Z operator-(const Z &lhs, const Z &rhs) {
        Z res = lhs;res -= rhs;
        return res;
    }
    friend Z operator/(const Z &lhs, const Z &rhs) {
        Z res = lhs;res /= rhs;
        return res;
    }
    friend std::istream &operator>>(std::istream &is, Z &a) {
        int v;is >> v;
        a = Z(v);
        return is;
    }
    friend std::ostream &operator<<(std::ostream &os, const Z &a) {
        return os << a.val();
    }
};

void solve(){
    int n;cin>>n;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];

    vector<int>v(n+1);
    vector<int>b(n+1,-1);
    auto decompose=[&](int x,int idx) -> void {
        for(int i=0;i<m;i++){
            int j=prime[i];
            while(x%j==0) v[idx]|=1<<i,x/=j;
        }
        if(x!=1) b[idx]=x;
    };
    
    for(int i=1;i<=n;i++){
        decompose(a[i],i);
    }
    vector<int>p(n+1);
    iota(p.begin()+1,p.end(),1);
    sort(p.begin()+1,p.end(),[&](int x,int y){
        return b[x]<b[y];
    });

    vector<Z>inv(m);
    for(int i=0;i<m;i++) inv[i]=(Z)1/prime[i];
    vector<Z>d(1<<m,1);
    for(int i=0;i<1<<m;i++){
        for(int j=0;j<m;j++){
            if(i>>j&1){
                d[i]*=(prime[j]-1);
                d[i]*=inv[j];
            }
        }
    }

    int L=1;
    // i 是prime是否出现的状压,j 是大质数是否出现过
    vector<array<Z,2>>f(1<<m),g(1<<m);
    
    f[0][0]=1;
    while(L<=n){
        int R=L+1;
        while(R<=n&&b[p[R]]==b[p[L]]) R++;
        for(int i=L;i<R;i++){
            int j=p[i];
            //不用a[j]
            g=f;
            //使用a[j]
            //转移 k->nx
            for(int k=0;k<1<<m;k++){
                int nx=k|v[j];
                int y=k&v[j];
                //新加的质数
                int t=v[j]-y;
                //要乘上的数
                Z mul=a[j];
                mul*=d[t];
                // for(int u=0;u<m;u++){
                //     if(t>>u&1){
                //         mul=mul/prime[u]*(prime[u]-1);
                //     }
                // }
                //是否是第一次加上这个最大质数
                if(b[j]!=-1){
                    g[nx][1]+=f[k][0]*(mul/b[j]*(b[j]-1));
                    g[nx][1]+=f[k][1]*mul;
                } else {
                    g[nx][0]+=f[k][0]*mul;
                }
            }
            f=g;
        }

        //转移到下一个状态
        for(int k=0;k<1<<m;k++){
            g[k][0]=g[k][1]=0;
            g[k][0]=f[k][1]+f[k][0];
        }
        f=g;

        L=R;
    }

    Z ans=0;
    for(int k=0;k<1<<m;k++){
        ans+=f[k][0];
    }
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 3ms
memory: 4432kb

input:

5
1 6 8 6 2

output:

892

result:

ok single line: '892'

Test #2:

score: 0
Accepted
time: 7ms
memory: 4328kb

input:

5
3 8 3 7 8

output:

3157

result:

ok single line: '3157'

Test #3:

score: -100
Time Limit Exceeded

input:

2000
79 1 1 1 1 1 1 2803 1 1 1 1 1 1 1609 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2137 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 613 1 499 1 211 1 2927 1 1 1327 1 1 1123 1 907 1 2543 1 1 1 311 2683 1 1 1 1 2963 1 1 1 641 761 1 1 1 1 1 1 1 1 1 1 1 1489 2857 1 1 1 1 1 1 1 1 1 1 1 1 1 967 1 821 1 1 1 1 2143 1861...

output:


result: