牛客网暑期ACM多校训练营(第十场

版权声明:转载之前请说你是博主的粉丝哦。 https://blog.csdn.net/qq_34921856/article/details/81916054

D Rikka with Prefix Sum
当时一直想着怎么维护,并没有想到每个值对询问的贡献。。
真的是太菜了。
题解说的比较详细了,你只需要推出那个式子就行了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int mod=998244353;
struct Query
{
    int type;
    int L,R;
    int w;
}q[maxn];
int sum[maxn];
//返回d=gcd(a,b);和对应于等式ax+by=d中的xy
long long extgcd(long long a,long long b,long long &x,long long &y)
{
    if(a==0&&b==0)return -1;//无最大公约数
    if(b==0){x=1;y=0;return a;}
    long long d=extgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;//返回gcd(a,b)
}
//****************求逆元******************************
//ax=1(mod n)
long long mod_reverse(long long a,long long n)
{
    long long x,y;
    long long d=extgcd(a,n,x,y);
    if(d==1)return (x%n+n)%n;
    return -1;
}
long long tab1[maxn*2],tab2[maxn*2];
void init()
{
    tab1[0]=1;
    for(int i=1;i<maxn*2;i++)
        tab1[i]=tab1[i-1]*i%mod;
    tab2[2*maxn-1]=mod_reverse(tab1[2*maxn-1],mod);
    for(int i=2*maxn-2;i>=0;i--)
        tab2[i]=tab2[i+1]*(i+1)%mod;
}
long long C(int a,int b)
{
    if(a<b)return 0;
    return tab1[a]*tab2[b]%mod*tab2[a-b]%mod;
}

int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(sum,0,sizeof(sum));
        int n,m;
        scanf("%d %d",&n,&m);
        int type,L,R,w;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&type);
            if(type==1)
            {
                scanf("%d %d %d",&L,&R,&w);
                q[i]=(Query){type,L,R,w};
            }
            else if(type==2)
            {
                q[i].type=2;
                sum[i]++;
            }
            else
            {
                scanf("%d %d",&L,&R);
                q[i].type=3;
                q[i].L=L;
                q[i].R=R;
            }
            sum[i]+=sum[i-1];
        }
        for(int i=1;i<=m;i++)if(q[i].type==3)
        {
            long long ans=0;
            for(int j=1;j<i;j++)if(q[j].type==1)
            {
                long long k=sum[i]-sum[j]+1;
                int L1=q[j].L,R1=q[j].R;
                int L2=q[i].L,R2=q[i].R;
                int w=q[j].w;
                long long tmp=((C(k+R2-L1,k)-C(k+R2-R1-1,k))%mod+mod)%mod*w%mod;
                long long tmp2=((C(k+L2-1-L1,k)-C(k+L2-1-R1-1,k))%mod+mod)%mod*w%mod;
                (ans+=((tmp-tmp2)%mod+mod)%mod)%=mod;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

E Rikka with Equation
这题一点思路都没有。。
首先你要推出每个f的值,也就是 a 1 x 1 + a 2 x 2 + a 3 x 3 + . . . + a n x n 0 ( m o d m ) ( x [ 0 , m ) ) 的方案数。
如果 g c d ( a 1 , a 2 . . . , a n , m ) = 1 ,那么不管前面n-1个x怎么选,最后一个都有值可以使等式成立,所以方案数为 m n 1 ,推广到一般情况,如果gcd值不为1,那么前面的n-1个x随便选,最后一个有gcd种取法。(博主也不知道怎么证。。)
有n个数, 2 n 1 个非空子集,假设它们的gcd都为1,那么答案就为
i = 1 n C ( n , i ) m i 1 = i = 0 n C ( n , i ) m i 1 m = ( m + 1 ) n 1 m
所以你只需要枚举m,然后算出每个m的因子的ans,再容斥一下就行了。至于为什么要容斥,因为假如一个数的因子有4,那么肯定也会有2,你对因子2进行计算的值会包括4的,所以你得减掉,使得每个数内的值都只是自己的。同时容斥的方向需要注意。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int mod=998244353;
long long inv_m;
int p[maxn];

void push(int x)
{
    for(int i=1;i*i<=x;i++)if(x%i==0)
    {
        if(i*i==x)
            p[i]++;
        else
        {
            p[i]++;
            p[x/i]++;
        }
    }
}

long long quick_mul(long long a,long long b)
{
    long long res=1;
    while(b)
    {
        if(b%2)res=res*a%mod;
        b/=2;
        a=a*a%mod;
    }
    return res;
}
long long inv(long long a,long long m)
{
    if(a==1)return 1;
    return inv(m%a,m)*(m-m/a)%m;
}

long long F(int m,int n)
{
    return ((quick_mul(m+1,n)-1)%mod+mod)%mod*inv_m%mod;
}
long long ct[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(p,0,sizeof(p));
        int n,M;
        scanf("%d %d",&n,&M);
        int b;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&b);
            push(b);
        }
        long long ans=((quick_mul(2,n)-1)%mod+mod)%mod;
        for(int i=2;i<=M;i++)
        {
            inv_m=inv(i,mod);
            vector<int>V;
            for(int j=1;j*j<=i;j++)if(i%j==0)
            {
                if(j*j==i)
                    V.push_back(j);
                else
                {
                    V.push_back(j);
                    V.push_back(i/j);
                }
            }
            sort(V.begin(),V.end());
            for(int j=0;j<V.size();j++)
                ct[j]=F(i,p[V[j]]);
            for(int j=V.size()-1;j>=0;j--)
            {
                for(int k=j+1;k<V.size();k++)
                    if(V[k]%V[j]==0)
                {
                    ct[j]-=ct[k];
                    ct[j]=(ct[j]%mod+mod)%mod;
                }
            }
            long long res=0;
            for(int j=0;j<V.size();j++)
                res=(res+1LL*V[j]*ct[j]%mod)%mod;
            ans^=res;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

F Rikka with Line Graph
式子博主在下面也推出来了,然而并不知道怎么往下做下去。。
看了题解才知道。。
唉。
没啥好说的。

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=505;
const int mod=998244353;
int mp[maxn][maxn];
int d[maxn][maxn];
int n;
void floyd()
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}


int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {

        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            scanf("%d",&mp[i][j]),d[i][j]=mp[i][j];
        floyd();
        long long ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<i;j++)
            {
                vector<int>V(n);
                for(int k=1;k<=n;k++)
                    V[k-1]=min(d[i][k],d[j][k]);
                sort(V.begin(),V.end());
                for(int k=0;k<V.size();k++)
                {
                    (ans+=1LL*(n-k-1)*V[k]%mod)%=mod;
                }
            }
        }
        long long factor=n*(n-1)/2-1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<i;j++)
            ans=(ans+factor*mp[i][j]%mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

H Rikka with Ants
这个题其实式子比较好推,但后面的类欧几里得博主没见过。。
最后的上限的计算也没见过,这里mark一下。
形如 a b x > c d x + m ( a b > c d ) 这样的不等式,它的值其实和普通的式子一样算。
所以你求出上限后,套用类欧就行了。

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
typedef long long ll;
long long a,b,c,d;
bool check(long long x)
{
    return c*(x+1)/d-a*x/b+1>0;
}
ll solve(ll a, ll b, ll c, ll n) {
    if (a == 0) return (((b / c) % mod) * ((n + 1) % mod)) % mod;
    if (a >= c || b >= c) {
    ll tmp;
    if (n & 1) tmp = (n % mod) * ((n + 1) / 2 % mod) % mod;
    else tmp = (n / 2 % mod) * ((n + 1) % mod) % mod;
    return (solve(a % c, b % c, c, n) + (a / c) * tmp % mod + ((b / c) % mod) * ((n + 1) % mod)) % mod;
  }
    //ll m = (a * n + b) / c;
  ll m;
  {
    ll d1 = n / c, m1 = n % c;
    m = a * d1 + (a * m1 + b) / c;
  }

    ll v = solve(c, c - b - 1, a, m - 1);
    return ((n % mod) * (m % mod) - v) % mod;
}



long long fd(long long a,long long b,long long c,long long n)
{
    return solve(a,b,c,n);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        //LL t;
        scanf("%lld %lld %lld %lld",&a,&b,&c,&d);
        if(a*d==b*c)
        {
            puts("-1");
            continue;
        }
        if(a*d<b*c)
        {
            swap(a,c);swap(b,d);
        }
        long long ans;

        ans=(c+d)*b/(d*a-c*b);
        //cout<<ans<<endl;
        long long res=(((fd(c,c,d,ans)-fd(a,0,b,ans))%mod+mod)%mod+ans+1)%mod;
        printf("%lld\n",res);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34921856/article/details/81916054