SDOI2017 Round1 解题报告

245 篇文章 0 订阅
211 篇文章 0 订阅

Day1

A product

题意简述

定义

f(0)=0,f(1)=1,f(n)=f(n1)+f(n2)(n2)

i=1nj=1mf(gcd(i,j))

多组数据,对 109+7 取模

数据范围

对10%的数据, 1n,m100
对30%的数据, 1n,m1000
对另外30%的数据, T3
对100%的数据, T1000,1n,m1000000

题解

10pts

O(n2) 枚举,现算gcd和f(强行 O(n3)

30pts

预处理f和gcd, O(n2)

60pts

考虑反演
首先题目要求的那个式子直接可以化成

d=1nf(d)i=1nj=1m[(i,j)=d]

这个比较显然
然后可以将指数用反演公式化一下
=d=1nf(d)i=1nij=1mj[(i,j)=1]

=d=1nf(d)t=1ntμ(t)ndtmdt

这样就可以 O((n+logn)n) 回答询问了
注意指数也比较大,利用欧拉定理 aφ(p)1(modp) ,指数直接对 109+6 取模就行了

100pts

T=dt ,我们放弃枚举d,改成枚举T,也就是由枚举倍数变成枚举约数,那么现在d是T的约数

=T=1n(d|Tf(d)μ(Td))nTmT

g(T)=d|Tf(d)μ(Td) ,现在只需要预处理出1..n的每一个g就可以实现 O(nlogn) 回答询问了
对于g的预处理我尝试了很多种方法,首先埃氏筛法是非常显然的,并且由于 μ 只有1和-1两种有价值的取值,那么就将1都记录下来,-1都记录成逆元,时间复杂度大概是 O(nloglogn)
还有一种方法大概是半年之前TA学长交给我的一种方法,但是当时没有系统地学过莫比乌斯反演,对卷积什么的也没有什么理解,那这里就再感谢一下ATP神犇
可以发现,只有当质因子次数都为1的时候 μ 才是有价值的,并且 106 范围内的数质因子个数非常少,所以可以先把要求的数质因数分解,然后用二进制压位表示当前数含有的质因子,这样的话复杂度基本上是 O(n(logn+28))
然后又向ATP神犇学习了一种更厉害的方法:在线筛的时候预处理出每一个数的最小值因子和除去最小值因子之外的数,然后分解质因数的时候只需要每一次除去最小质因子就行了,这样理论复杂度上限应该是 O(n(8+28))
其实理论上说埃氏筛法的复杂度应该是更优越的,但是它牵扯到大量的乘除运算,常数比较大;并且二进制压位的方法用位运算,并且由于质因子数非常少远远达不到理论复杂度上限,所以速度更加优秀。

这道题当时考试的时候只做出来了60分,并且调试的时间也稍微有点长。主要让我困惑的是连加和连乘放在了一起就没办法搞出来一个科学的卷积或者相似的形式了。其实考试之前花了很长一段时间练习反演是见到了很多枚举约数改成枚举倍数的题目的,但是感觉当时没有认真想,以前的题目全部都是连加好像怎么都是对的,于是一变形式就不会了。实际上再往下画一画是不难的。
所以以后再思维方面是绝不能偷懒了。

代码

60pts

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define Mod 1000000007
#define phi 1000000006
#define N 1000005
#define LL long long

int T,n,m;
LL ans;
int p[N],prime[N];
LL mu[N],f[N];

void get(int n)
{
    f[0]=0;f[1]=1;
    for (int i=2;i<=n;++i) f[i]=(f[i-1]+f[i-2])%Mod;
    for (int i=2;i<=n;++i) f[i]=(f[i]*f[i-1])%Mod;

    mu[1]=1;
    for (int i=2;i<=n;++i)
    {
        if (!p[i])
        {
            prime[++prime[0]]=i;
            mu[i]=-1;
        }
        for (int j=1;j<=prime[0]&&i*prime[j]<=n;++j)
        {
            p[i*prime[j]]=1;
            if (i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            else mu[i*prime[j]]=-mu[i];
        }
    }
    for (int i=1;i<=n;++i) mu[i]=(mu[i]+mu[i-1])%phi;
}
LL fast_pow(LL a,LL p,LL mod)
{
    LL ans=1;
    for (;p;p>>=1LL,a=a*a%mod)
        if (p&1)
            ans=ans*a%mod;
    return ans;
}
LL sum(int n,int m)
{
    LL ans=0;
    if (n>m) swap(n,m);
    for (int i=1,j=0;i<=n;i=j+1)
    {
        j=min(n/(n/i),m/(m/i));
        ans=(ans+(LL)(n/i)*(m/i)%phi*(mu[j]-mu[i-1])%phi)%phi;
    }
    ans=(ans+phi)%phi;
    return ans;
}
int main()
{
    freopen("product.in","r",stdin);
    freopen("product.out","w",stdout);
    get(1000000);
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        if (n>m) swap(n,m);
        ans=1;
        for (int i=1,j=0;i<=n;i=j+1)
        {
            j=min(n/(n/i),m/(m/i));
            LL now=f[j];
            if (i!=1) now=now*fast_pow(f[i-1],Mod-2,Mod)%Mod;
            LL s=sum(n/i,m/i);
            now=fast_pow(now,s,Mod);
            ans=(ans*now)%Mod;
        }
        ans=(ans+Mod)%Mod;
        printf("%I64d\n",ans);
    }
}

埃氏筛法

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define Mod 1000000007
#define phi 1000000006
#define LL long long
#define N 1000005

int T,n,m;
int p[N],prime[N],mu[N];
LL ans;
LL f[N],g[N],inv[N];
LL fast_pow(LL a,int p)
{
    LL ans=1;
    for (;p;p>>=1,a=a*a%Mod)
        if (p&1)
            ans=ans*a%Mod;
    return ans;
}
void get(int n)
{
    f[0]=0;f[1]=1;
    for (int i=2;i<=n;++i) f[i]=(f[i-1]+f[i-2])%Mod;

    mu[1]=1;
    for (int i=2;i<=n;++i)
    {
        if (!p[i])
        {
            prime[++prime[0]]=i;
            mu[i]=-1;
        }
        for (int j=1;j<=prime[0]&&i*prime[j]<=n;++j)
        {
            p[i*prime[j]]=1;
            if (i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            else mu[i*prime[j]]=-mu[i];
        }
    }

    for (int i=1;i<=n;++i) g[i]=inv[i]=1;
    for (int i=1;i<=n;++i)
        for (int j=i;j<=n;j+=i)
        {
            int t=j/i;
            if (mu[t]==1) g[j]=g[j]*f[i]%Mod;
            else if (mu[t]==-1) inv[j]=inv[j]*f[i]%Mod;
        }
    for (int i=1;i<=n;++i) g[i]=g[i]*fast_pow(inv[i],Mod-2)%Mod;
    for (int i=2;i<=n;++i) g[i]=g[i]*g[i-1]%Mod;
}
int main()
{
    freopen("product.in","r",stdin);
    freopen("product.out","w",stdout);
    get(1000000);
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        if (n>m) swap(n,m);
        ans=1;
        for (int i=1,j=0;i<=n;i=j+1)
        {
            j=min(n/(n/i),m/(m/i));
            LL a=(LL)(n/i)*(m/i)%phi;
            LL now=g[j];
            if (i!=1) now=now*fast_pow(g[i-1],Mod-2)%Mod;
            ans=ans*fast_pow(now,(int)a)%Mod;
        }
        printf("%I64d\n",ans);
    }
}

暴力分解质因数

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define Mod 1000000007
#define phi 1000000006
#define LL long long
#define N 1000005

int T,n,m;
int p[N],prime[N],mu[N],d[1<<8];
LL ans;
LL f[N],g[N],inv[N];
LL fast_pow(LL a,int p)
{
    LL ans=1;
    for (;p;p>>=1,a=a*a%Mod)
        if (p&1)
            ans=ans*a%Mod;
    return ans;
}
void get(int n)
{
    f[0]=0;f[1]=1;
    for (int i=2;i<=n;++i) f[i]=(f[i-1]+f[i-2])%Mod;

    mu[1]=1;
    for (int i=2;i<=n;++i)
    {
        if (!p[i])
        {
            prime[++prime[0]]=i;
            mu[i]=-1;
        }
        for (int j=1;j<=prime[0]&&i*prime[j]<=n;++j)
        {
            p[i*prime[j]]=1;
            if (i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            else mu[i*prime[j]]=-mu[i];
        }
    }

    for (int T=1;T<=n;++T)
    {
        g[T]=inv[T]=1;
        int totp=0;memset(d,0,sizeof(d));
        int x=T;
        for (int i=1;i<=prime[0]&&prime[i]*prime[i]<=x&&x>1;++i)
            if (x%prime[i]==0)
            {
                ++totp,d[1<<(totp-1)]=prime[i];
                while (x%prime[i]==0) x/=prime[i];
            }
        if (x>1) ++totp,d[1<<(totp-1)]=x;
        for (int i=0;i<1<<totp;++i)
        {
            if (i) d[i]=d[i^(i&-i)]*d[i&-i];
            else d[i]=1;
            int t=T/d[i];
            if (mu[d[i]]==1) g[T]=g[T]*f[t]%Mod;
            else if (mu[d[i]]==-1) inv[T]=inv[T]*f[t]%Mod;
        }
    }
    for (int i=1;i<=n;++i) g[i]=g[i]*fast_pow(inv[i],Mod-2)%Mod;
    for (int i=2;i<=n;++i) g[i]=g[i]*g[i-1]%Mod;
}
int main()
{
    freopen("product.in","r",stdin);
    freopen("product.out","w",stdout);
    get(1000000);
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        if (n>m) swap(n,m);
        ans=1;
        for (int i=1,j=0;i<=n;i=j+1)
        {
            j=min(n/(n/i),m/(m/i));
            LL a=(LL)(n/i)*(m/i)%phi;
            LL now=g[j];
            if (i!=1) now=now*fast_pow(g[i-1],Mod-2)%Mod;
            ans=ans*fast_pow(now,(int)a)%Mod;
        }
        printf("%I64d\n",ans);
    }
}

orz ATP

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define Mod 1000000007
#define phi 1000000006
#define LL long long
#define N 1000005

int T,n,m;
int p[N],prime[N],mu[N],e[N],h[N],d[1<<8];
LL ans;
LL f[N],g[N],inv[N];
LL fast_pow(LL a,int p)
{
    LL ans=1;
    for (;p;p>>=1,a=a*a%Mod)
        if (p&1)
            ans=ans*a%Mod;
    return ans;
}
void get(int n)
{
    f[0]=0;f[1]=1;
    for (int i=2;i<=n;++i) f[i]=(f[i-1]+f[i-2])%Mod;

    mu[1]=1;
    for (int i=2;i<=n;++i)
    {
        if (!p[i])
        {
            prime[++prime[0]]=i;
            mu[i]=-1;
            e[i]=i;
            h[i]=1;
        }
        for (int j=1;j<=prime[0]&&i*prime[j]<=n;++j)
        {
            p[i*prime[j]]=1;
            if (i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                e[i*prime[j]]=e[i];
                h[i*prime[j]]=h[i];
                break;
            }
            else
            {
                mu[i*prime[j]]=-mu[i];
                e[i*prime[j]]=prime[j];
                h[i*prime[j]]=i;
            }
        }
    }

    for (int T=1;T<=n;++T)
    {
        g[T]=inv[T]=1;
        int totp=0;memset(d,0,sizeof(d));
        int x=T;
        while (x>1) 
            ++totp,d[1<<(totp-1)]=e[x],x=h[x];
        for (int i=0;i<1<<totp;++i)
        {
            if (i) d[i]=d[i^(i&-i)]*d[i&-i];
            else d[i]=1;
            int t=T/d[i];
            if (mu[d[i]]==1) g[T]=g[T]*f[t]%Mod;
            else if (mu[d[i]]==-1) inv[T]=inv[T]*f[t]%Mod;
        }
    }
    for (int i=1;i<=n;++i) g[i]=g[i]*fast_pow(inv[i],Mod-2)%Mod;
    for (int i=2;i<=n;++i) g[i]=g[i]*g[i-1]%Mod;
}
int main()
{
    freopen("product.in","r",stdin);
    freopen("product.out","w",stdout);
    get(1000000);
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        if (n>m) swap(n,m);
        ans=1;
        for (int i=1,j=0;i<=n;i=j+1)
        {
            j=min(n/(n/i),m/(m/i));
            LL a=(LL)(n/i)*(m/i)%phi;
            LL now=g[j];
            if (i!=1) now=now*fast_pow(g[i-1],Mod-2)%Mod;
            ans=ans*fast_pow(now,(int)a)%Mod;
        }
        printf("%I64d\n",ans);
    }
}

B paint

题意简述

一棵n个点并且以1号点为根的有根树,初始时每个点都有一种不同的颜色,定义一条路径的权值为路径上的颜色种类数。
有三个操作:
1 x 将x到根的路径上的所有点染上一种没有用过的新颜色
2 x y 询问树链xy的权值
3 x 在以x为根的子树中选择一个点,使这个点到根节点的路径权值最大,求最大权值
对于m个操作中的每一个2或3操作输出答案。

数据范围

对10%的数据, 1n,m1000
对另外20%的数据,没有2操作
对另外20%的数据,没有3操作
对另外10%的数据,数据随机
对100%的数据, 1n,m100000

题解

10pts

暴力暴力
每一次暴力修改暴力统计颜色数,修改之后要重新dfs
O(n2)

20pts

链剖统计区间颜色段数

10pts

数据随机不用谢手工栈hhh

100pts

这道题的关键是每一次都是将某一个点到根的路径上的点染一种没用过的新颜色
这个操作实际上和lct中的access操作很像,因为都是打通一条到根的路径
那么我们就可以将重边的贡献记为0,轻边的贡献记为1,每一个点的权记为根到当前点的边的贡献和,那么2操作实际上就是计算val(x)+val(y)-2*val(lca(x,y))+1,3操作实际上就是求以x为根的子树的权值最大值+1
那么就可以维护一个有根树的lct,然后在砍断一条重边的时候和连接一条重边的时候都对这条边相连的子树进行修改,这样就相当于是一个区间修改单点查询权值和一个区间修改区间查询最大值的问题,写两棵线段树就行了

这道题考试的时候没有什么科学的思路。。只打了10分暴力,还打跪了。。需要注意的是两个点暴力向上蹦的时候一定要注意像lca一样判断是否蹦到同一个点什么的,这个不能再出错了
这道题其实之前见过,是fye学姐暑假的一次胡策,当时没有做。。。感觉在考场上想出来不是不可能但是也是有难度的,看来以后见过的题一定要搞懂它,做过的题也要经常复习呀

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 100005
#define sz 17

int n,m,dfs_clock;
int tot,point[N],nxt[N*2],v[N*2];
int father[N],h[N],in[N],out[N],val[N],pt[N],f[N][sz+3];
int fa[N],ch[N][2];
int sum[N*4],maxn[N*4],delta[N*4];

//-----------------------------init------------------------------------
void add(int x,int y)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void dfs(int x,int fa)
{
    father[x]=fa;h[x]=h[fa]+1;
    in[x]=++dfs_clock;pt[dfs_clock]=x;
    for (int i=1;i<sz;++i) f[x][i]=f[f[x][i-1]][i-1];
    for (int i=point[x];i;i=nxt[i])
        if (v[i]!=fa)
        {
            f[v[i]][0]=x;
            dfs(v[i],x);
        }
    out[x]=dfs_clock;
}
//-----------------------------lca-------------------------------------
int lca(int x,int y)
{
    if (h[x]<h[y]) swap(x,y);
    int k=h[x]-h[y];
    for (int i=0;i<sz;++i)
        if (k>>i&1) x=f[x][i];
    if (x==y) return x;
    for (int i=sz-1;i>=0;--i)
        if (f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
//----------------------------segtree----------------------------------
void update(int now)
{
    sum[now]=sum[now<<1]+sum[now<<1|1];
    maxn[now]=max(maxn[now<<1],maxn[now<<1|1]);
}
void pushdown(int now,int l,int r,int mid)
{
    if (delta[now])
    {
        sum[now<<1]+=delta[now]*(mid-l+1);sum[now<<1|1]+=delta[now]*(r-mid);
        maxn[now<<1]+=delta[now];maxn[now<<1|1]+=delta[now];
        delta[now<<1]+=delta[now];delta[now<<1|1]+=delta[now];
        delta[now]=0;
    }
}
void build(int now,int l,int r)
{
    int mid=(l+r)>>1;
    if (l==r)
    {
        sum[now]=maxn[now]=h[pt[l]]-1;
        return;
    }
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    update(now);
}
void change(int now,int l,int r,int lr,int rr,int x)
{
    int mid=(l+r)>>1;
    if (lr<=l&&r<=rr)
    {
        sum[now]+=x*(r-l+1);
        maxn[now]+=x;
        delta[now]+=x;
        return;
    }
    pushdown(now,l,r,mid);
    if (lr<=mid) change(now<<1,l,mid,lr,rr,x);
    if (mid+1<=rr) change(now<<1|1,mid+1,r,lr,rr,x);
    update(now);
}
int query_sum(int now,int l,int r,int lr,int rr)
{
    int mid=(l+r)>>1,ans=0;
    if (lr<=l&&r<=rr) return sum[now];
    pushdown(now,l,r,mid);
    if (lr<=mid) ans+=query_sum(now<<1,l,mid,lr,rr);
    if (mid+1<=rr) ans+=query_sum(now<<1|1,mid+1,r,lr,rr);
    return ans;
}
int query_max(int now,int l,int r,int lr,int rr)
{
    int mid=(l+r)>>1,ans=0;
    if (lr<=l&&r<=rr) return maxn[now];
    pushdown(now,l,r,mid);
    if (lr<=mid) ans=max(ans,query_max(now<<1,l,mid,lr,rr));
    if (mid+1<=rr) ans=max(ans,query_max(now<<1|1,mid+1,r,lr,rr));
    return ans;
}
//------------------------------lct------------------------------------
bool isroot(int x)
{
    return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
int get(int x)
{
    return ch[fa[x]][1]==x;
}
void rotate(int x)
{
    int old=fa[x],oldf=fa[old],wh=get(x);
    if (!isroot(old)) ch[oldf][ch[oldf][1]==old]=x;
    fa[x]=oldf;
    ch[old][wh]=ch[x][wh^1];
    if (ch[old][wh]) fa[ch[old][wh]]=old;
    ch[x][wh^1]=old;
    fa[old]=x;
}
void splay(int x)
{
    for (int old;!isroot(x);rotate(x))
        if (!isroot(old=fa[x]))
            rotate((get(x)==get(old))?old:x);
}
int find(int x)
{
    while (ch[x][0]) x=ch[x][0];
    return x;
}
void access(int x)
{
    int t=0;
    for (;x;t=x,x=fa[x])
    {
        splay(x);
        if (ch[x][1])
        {
            int rt=find(ch[x][1]);
            change(1,1,n,in[rt],out[rt],1);
        }
        ch[x][1]=t;
        if (t)
        {
            int rt=find(t);
            change(1,1,n,in[rt],out[rt],-1);
        }
    }
}
//------------------------------main-----------------------------------
int main()
{
    freopen("paint.in","r",stdin);
    freopen("paint.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<n;++i)
    {
        int x,y;scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    dfs(1,0);
    build(1,1,n);
    for (int i=1;i<=n;++i) fa[i]=father[i];
    while (m--)
    {
        int opt;scanf("%d",&opt);
        if (opt==1)
        {
            int x;scanf("%d",&x);
            access(x);
        }
        else if (opt==2)
        {
            int x,y;scanf("%d%d",&x,&y);
            int r=lca(x,y),old=father[r];
            int ans=query_sum(1,1,n,in[x],in[x])+query_sum(1,1,n,in[y],in[y]);
            ans-=query_sum(1,1,n,in[r],in[r])*2;
            printf("%d\n",ans+1);
        }
        else if (opt==3)
        {
            int x;scanf("%d",&x);
            int ans=query_max(1,1,n,in[x],out[x]);
            printf("%d\n",ans+1);
        }
    }
}

C count

题意简述

求有多少个序列,满足:共有n个数,每一个数都是不超过m的整数,这n个数的和为p的倍数,并且这n个数中至少有一个为质数。
对20140408取模。

数据范围

对于20%的数据, 1n100,1m100
对于50%的数据, 1m100
对于80%的数据, 1m106
对于100%的数据, 1n109,1m2107,1p100

题解

20pts

首先容斥一下
令f(i,j)表示前i个数,和为j,没有一个数是质数的方案数
令g(i,j)表示前i个数,和为j的方案数
然后枚举p的每一个倍数k,计算 g(n,k)f(n,k)

100pts

令f(i,j)表示前i个数,和对p取模之后为j,没有一个数是质数的方案数
令g(i,j)表示前i个数,和对p取模之后为j的方案数
那么答案应该是g(n,0)-f(n,0)
只需要线筛预处理出来 2107 范围内的数有多少个对p取模为i,不是质数的数有多少个对p取模为i就可以实现 O(np) 枚举 O(p) 转移了
由于n比较大,可以用矩乘优化
构造矩阵时,如果f(i,j)能转移到f(i+1,k),系数为w,那么就在转移矩阵的第i行第j列置w,这样构造矩阵的复杂度是 O(p2)
总时间 O(lognp3)

这道题在考场上拿到了满分,写的时间也不算长,还是比较好的。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define Mod 20170408
#define LL long long

int n,m,p;
int prime[2000005];
bool isp[20000005];
LL cnt[105][2],ans;
struct data{LL a[105][105];}unit,f,g,F,G;

void get(int n)
{
    isp[1]=1;
    for (int i=2;i<=n;++i)
    {
        if (!isp[i]) prime[++prime[0]]=i;
        for (int j=1;j<=prime[0]&&i*prime[j]<=n;++j)
        {
            isp[i*prime[j]]=1;
            if (i%prime[j]==0) break;
        }
    }
    for (int i=1;i<=n;++i)
    {
        if (isp[i])
        {
            ++cnt[i%p][0];
            if (cnt[i%p][0]==Mod) cnt[i%p][0]=0;
        }
        ++cnt[i%p][1];
        if (cnt[i%p][1]==Mod) cnt[i%p][1]=0;
    }   
}
data cheng(data a,data b)
{
    data ans;memset(ans.a,0,sizeof(ans.a));
    for (int k=0;k<p;++k)
        for (int i=0;i<p;++i)
            for (int j=0;j<p;++j)
                ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j]%Mod)%Mod;
    return ans;
}
data fast_pow(data a,int p)
{
    data ans=unit;
    for (;p;p>>=1,a=cheng(a,a))
        if (p&1)
            ans=cheng(ans,a);
    return ans;
}
int main()
{
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    scanf("%d%d%d",&n,&m,&p);
    get(m);
    for (int i=0;i<p;++i) unit.a[i][i]=1;
    for (int i=0;i<p;++i)
    {
        f.a[0][i]=cnt[i][0];
        g.a[0][i]=cnt[i][1];
    }
    for (int i=0;i<p;++i)
        for (int j=0;j<p;++j)
        {
            F.a[i][(i+j)%p]=cnt[j][0];
            G.a[i][(i+j)%p]=cnt[j][1];
        }
    F=fast_pow(F,n-1);
    G=fast_pow(G,n-1);
    f=cheng(f,F);
    g=cheng(g,G);
    ans=g.a[0][0]-f.a[0][0];
    ans=(ans+Mod)%Mod;
    printf("%I64d\n",ans);
}

Day2

A ball

题意简述

有n个男生和n个女生,其中第i个男生和第j个女生配对的数据分别为 aij bij
求一种配对方案,使 aijbij 最大

数据范围

对10%的数据, 1n5
对40%的数据, 1n18
对另外20%的数据, bij=1
对100%的数据, 1n100,1ai,j,bi,j104

题解

10pts

O(n!n) 暴力枚举+判断

40pts

据说是给写正解结果tle的人的?

60pts

因为分母一定,直接是最大权值匹配,费用流即可

100pts

这个式子一看就是01分数规划嘛
首先二分答案,设 aijbij=mid ,那么当 aijbijmid aijbijmid0 的时候说明还存在更优解
于是每一次将两个人的配对的权值改成 aijbijmid 然后用费用流做最大权值匹配,若匹配出来大于或等于0说明还有更优解
faebdc的做法是将所有的数扩大 107 这样来避免精度误差,感觉很厉害啊
向ATP学习了KM算法了之后又写了一遍,真的跑的好快啊

这道题在考场上拿到了90分,10分是因为精度问题。因为当时怕tle所以将精度开得较大。这种小问题如果再对拍久一些的话是有可能发现的,以后注意吧

代码

费用流

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

const double eps=1e-8;
int n,s,t,maxflow;
int tot,point[210],nxt[31000],v[31000],remain[31000],last[210];double c[31000];
double ans,maxcost;
double a[105][105],b[105][105],dis[210];bool vis[210];
queue <int> q;

void addedge(int x,int y,int cap,double z)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cap; c[tot]=z;
    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; c[tot]=-z;
}
int addflow(int s,int t)
{
    int now=t,ans=1000000000;
    while (now!=s)
    {
        ans=min(ans,remain[last[now]]);
        now=v[last[now]^1];
    }
    now=t;
    while (now!=s)
    {
        remain[last[now]]-=ans;
        remain[last[now]^1]+=ans;
        now=v[last[now]^1];
    }
    return ans;
}
bool spfa(int s,int t)
{
    for (int i=1;i<=t;++i) dis[i]=-1e9;dis[s]=0;
    memset(vis,0,sizeof(vis));vis[s]=1;
    q.push(s);
    while (!q.empty())
    {
        int now=q.front();q.pop();
        vis[now]=0;
        for (int i=point[now];i!=-1;i=nxt[i])
            if (dis[v[i]]-dis[now]-c[i]<-eps&&remain[i])
            {
                dis[v[i]]=dis[now]+c[i];
                last[v[i]]=i;
                if (!vis[v[i]]) vis[v[i]]=1,q.push(v[i]);
            }
    }
    if (dis[t]==-1e9) return 0;
    int flow=addflow(s,t);
    maxflow+=flow;
    maxcost+=(double)flow*dis[t];
    if (maxcost<-eps) return 0;
    return 1;
}
bool check(double mid)
{
    tot=-1;memset(point,-1,sizeof(point));
    s=n+n+1,t=s+1;
    for (int i=1;i<=n;++i) addedge(s,i,1,0),addedge(n+i,t,1,0);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            addedge(i,n+j,1,a[i][j]-mid*b[i][j]);
    maxflow=0;maxcost=0.0;
    while (spfa(s,t));
    return maxcost>=-eps;
}
double find()
{
    double l=1,r=1e4,mid,ans=0;
    while (r-l>eps)
    {
        mid=(l+r)/2.0;
        if (check(mid)) ans=l=mid;
        else r=mid;
    }
    return ans;
}
int main()
{
    freopen("ball.in","r",stdin);
    freopen("ball.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            scanf("%lf",&a[i][j]);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            scanf("%lf",&b[i][j]);
    ans=find();
    printf("%.6lf\n",ans);
}

KM

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

const double eps=1e-8;
const double inf=1e9;
int n,mak;
int link[105],vis[210];
double ans;
double a[105][105],b[105][105],ex[105],ey[105],e[105][105],lak[105];

bool find(int x,int mak)
{
    vis[x]=mak;
    for (int i=1;i<=n;++i)
        if (vis[i+n]!=mak)
        {
            double tmp=ex[x]+ey[i]-e[x][i];
            if (fabs(tmp)<eps)
            {
                vis[i+n]=mak;
                if (link[i]==-1||find(link[i],mak))
                {
                    link[i]=x;
                    return 1;
                }
            }
            else lak[i]=min(lak[i],tmp);
        }
    return 0;
}
double KM()
{
    double sum=0;
    for (int i=1;i<=n;++i)
    {
        ex[i]=-inf;
        for (int j=1;j<=n;++j)
            ex[i]=max(ex[i],e[i][j]);
    }
    memset(ey,0,sizeof(ey));
    for (int i=1;i<=n;++i)
    {
        for (int j=1;j<=n;++j) lak[j]=inf;
        while (1)
        {
            ++mak;
            if (find(i,mak)) break;
            double tmp=inf;
            for (int k=1;k<=n;++k)
                if (vis[k+n]!=mak) tmp=min(tmp,lak[k]);
            for (int k=1;k<=n;++k)
            {
                if (vis[k]==mak) ex[k]-=tmp;
                if (vis[k+n]==mak) ey[k]+=tmp;
                else lak[k]-=tmp;
            }
        }
    }
    for (int i=1;i<=n;++i)
        if (link[i]!=-1)
            sum+=e[link[i]][i];
    return sum;
}
bool check(double mid)
{
    memset(vis,0,sizeof(vis));
    mak=0;memset(link,-1,sizeof(link));
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            e[i][j]=(double)a[i][j]-mid*b[i][j];
    double ans=KM();
    return ans>-eps;
}
double find()
{
    double l=1,r=1e4,mid,ans=0;
    while (r-l>eps)
    {
        mid=(l+r)/2.0;
        if (check(mid)) ans=l=mid;
        else r=mid;
    }
    return ans;
}
int main()
{
    freopen("ball.in","r",stdin);
    freopen("ball.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            scanf("%lf",&a[i][j]);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            scanf("%lf",&b[i][j]);
    ans=find();
    printf("%.6lf\n",ans);
}

B game

题意简述

有n个人,每一个人有一个由H和T组成,长度为m的序列,并且这n个序列两两不同。
现在要一位一位构造一个新的序列,其中每一个位置是H和T的概率相等,并且如果n个序列中某一个序列i在这个新序列中出现了,那么立刻停止,并且判第i个人获胜。
求每一个人获胜的概率。
相对误差 106 即为正确。

数据范围

对10%的数据, 1n,m3
对40%的数据, 1n,m18
对另外20%的数据, n=2
对100%的数据, 1n,m300

题解

10pts

考虑状压dp,f(i,s)表示选了i个,最后m个状态为s的概率
因为做了很多次了之后概率就变得非常小了,所以当i比较大的时候就非常接近答案了

40pts

同样是dp,先对n个串建立AC自动机,然后f(i,j)表示选了i个,匹配到自动机的第j个节点的概率
同样是做很多次,但是这样的话自动机的状态非常少,比之前的状压的方法要优越一些

100pts

这道题的关键思路是用一个变量 P(N) 直接表示所有没有到达终止点的概率
若两个串是TTH和HTT,假设 P(A) P(B) 分别表示到达这两个人的终止点的概率
那么如果N接上TTH,那么一定到达了一个终止点,但是有可能到不了最后一个T就结束了,因为可能到达了B的结束状态,所以考虑所有的可能性可以得到

P(N+TTH)=P(A)+P(B+TH)+P(B+H)

其实就是得到了一个方程
0.125P(N)=P(A)+0.25P(B)+0.5P(B)

0.125P(N)=P(A)+0.75P(B)

这样的话,加上所有人胜利的概率总和为1,我们可以得到n+1个方程n+1个未知数,高斯消元求解即可
不过还有一个问题就是怎么确定系数,可以发现如果一个串的某些前缀是另一个串的某些后缀的话它们是可以产生系数的
所以这里有两种方法,一个是将所有的串两两连接起来用kmp求出来失配,然后暴力地蹦失配计算系数;另一种是建立AC自动机然后每一次蹦fail,由于自动机上的每一个点可以是很多个串的节点,所以可以对每一个点加一个链表。
两个方法我都写了一下,发现kmp的最大优势是代码复杂度和空间。

这道题在考试的时候只拿到了10分,想到了AC自动机,但是没有想到在AC自动机上dp,更没有想到正解。
感觉这道题的思路还是很巧妙的。

代码

kmp

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 605

int n,m,len;
char s[N][N],w[N];
int T[N];
double mi[N],a[N][N],b[N],ans[N];

void calc_T()
{
    memset(T,0,sizeof(T));
    T[0]=-1;
    for (int i=0;i<len;++i)
    {
        int j=T[i];
        while (j!=-1&&w[i]!=w[j])
            j=T[j];
        T[i+1]=++j;
    }
}
void gauss()
{
    for (int i=1;i<=n+1;++i)
    {
        int num=i;
        for (int j=i+1;j<=n+1;++j)
            if (fabs(a[j][i])>fabs(a[i][i])) num=j;
        if (num!=i)
        {
            for (int j=1;j<=n+1;++j) swap(a[i][j],a[num][j]);
            swap(b[i],b[num]);
        }
        for (int j=i+1;j<=n+1;++j)
            if (fabs(a[j][i]))
            {
                double t=a[j][i]/a[i][i];
                for (int k=1;k<=n+1;++k)
                    a[j][k]-=t*a[i][k];
            }
    }
    for (int i=n+1;i>=1;--i)
    {
        for (int j=i+1;j<=n+1;++j) b[i]-=a[i][j]*ans[j];
        ans[i]=b[i]/a[i][i];
    }
}
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i) scanf("%s",s[i]+1);
    mi[0]=1.0;for (int i=1;i<=m;++i) mi[i]=mi[i-1]*0.5;
    for (int i=1;i<=n;++i)
    {
        a[i][n+1]=-mi[m];
        for (int j=1;j<=n;++j)
        {
            len=0;
            for (int k=1;k<=m;++k) w[len++]=s[i][k];
            w[len++]='$';
            for (int k=1;k<=m;++k) w[len++]=s[j][k];
            calc_T();
            int now=T[len];
            while (now>0)
            {
                a[i][j]+=mi[m-now];
                now=T[now];
            }
        }
    }
    for (int i=1;i<=n;++i) a[n+1][i]=1.0;
    b[n+1]=1.0;
    gauss();
    for (int i=1;i<=n;++i) printf("%.10lf\n",ans[i]);
}

AC自动机

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
#define N 305

int n,m,sz;
char s[N][N];
int ch[N*N][2],fail[N*N],h[N*N],is_end[N*N],pt[N];
int tot,point[N*N],nxt[N*N],v[N*N];
double mi[N],a[N][N],b[N],ans[N];
queue <int> q;

void add(int x,int y)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void insert(int id)
{
    int now=0;
    for (int i=1;i<=m;++i)
    {
        int x=(s[id][i]=='T')?1:0;
        if (!ch[now][x]) ch[now][x]=++sz;
        h[ch[now][x]]=h[now]+1;
        now=ch[now][x];
        is_end[now]=1;
        add(now,id);
    }
    pt[id]=now;
}
void make_fail()
{
    for (int i=0;i<=1;++i)
        if (ch[0][i]) q.push(ch[0][i]);
    while (!q.empty())
    {
        int now=q.front();q.pop();
        for (int i=0;i<=1;++i)
        {
            if (!ch[now][i])
            {
                ch[now][i]=ch[fail[now]][i];
                continue;
            }
            fail[ch[now][i]]=ch[fail[now]][i];
            q.push(ch[now][i]);
        }
    }
}
void gauss()
{
    for (int i=1;i<=n+1;++i)
    {
        int num=i;
        for (int j=i+1;j<=n+1;++j)
            if (fabs(a[j][i])>fabs(a[i][i])) num=j;
        if (num!=i)
        {
            for (int j=1;j<=n+1;++j) swap(a[i][j],a[num][j]);
            swap(b[i],b[num]);
        }
        for (int j=i+1;j<=n+1;++j)
            if (fabs(a[j][i]))
            {
                double t=a[j][i]/a[i][i];
                for (int k=1;k<=n+1;++k)
                    a[j][k]-=t*a[i][k];
            }
    }
    for (int i=n+1;i>=1;--i)
    {
        for (int j=i+1;j<=n+1;++j) b[i]-=a[i][j]*ans[j];
        ans[i]=b[i]/a[i][i];
    }
}
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%d%d",&n,&m);
    mi[0]=1.0;for (int i=1;i<=m;++i) mi[i]=mi[i-1]*0.5;
    for (int i=1;i<=n;++i)
    {
        scanf("%s",s[i]+1);
        insert(i);
    }
    make_fail();
    for (int i=1;i<=n;++i)
    {
        a[i][n+1]=-mi[m];
        int now=pt[i];
        while (now)
        {
            if (is_end[now])
            {
                for (int j=point[now];j;j=nxt[j])
                    a[v[j]][i]+=mi[m-h[now]];
            }
            now=fail[now];
        }
    }
    for (int i=1;i<=n;++i) a[n+1][i]=1.0;
    b[n+1]=1.0;
    gauss();
    for (int i=1;i<=n;++i) printf("%.10lf\n",ans[i]);
}

C relative

题意简述

有两个n个数的数列 xi yi ,有m个操作,3种操作类型
1 L R x¯=1RL+1i=LRxi,y¯=1RL+1i=LRyi ,计算 a=i=LR(xix¯)(yiy¯)i=LR(xix¯)2
2 L R S T 对于每一个 LiR xi 加上S, yi 加上T
3 L R S T 对于每一个 LiR xi 修改为(S+i), yi 修改为(T+i)

数据范围

对20%的数据, 1n,m1000
对另外20%的数据,没有3操作,且2操作中S=0
对另外30%的数据,没有3操作
对于100%的数据, 1n,m105,1LRn,0|S|,|T|105,0|xi|,|yi|105

题解

20pts

暴力暴力

100pts

首先将要求的a的式子划开来,变成

a=i=LRxiyix¯i=LRyiy¯i=LRxi+x¯y¯(RL+1)i=LRx2i2x¯i=LRxi+x¯2(RL+1)

这样的话可以发现我们只需要用线段树维护4个量:1、 xiyi 的区间和 2、 x2i 的区间和 3、 xi 的区间和 4、 yi 的区间和
后两个随便维护一下就行了,关键是前两个,其实,前两个是可以根据后两个推出来的
首先对于2操作:
i=LRxiyi=i=LR(xi+S)(yi+T)=i=LRxiyi+Ti=LRxi+Si=LRyi+ST(RL+1)
i=LRx2i=i=LR(xi+S)2=i=LRx2i+2Si=LRxi+S2(RL+1)
这样就可以维护了
对于3操作:
i=LRxiyi=i=LR(S+i)(T+i)=ST(RL+1)+Si=LRi+Ti=LRi+i=LRi2
i=LRx2i=i=LR(S+i)2=S2(RL+1)+2si=LRi+i=LRi2
可以发现 i=LRi i=LRi2 都是可以用前缀和预处理的,所以这个也可以维护了
所以我们需要维护4个标记:1、S的加法 2、S的覆盖 3、T的加法 4、T的覆盖
然后这就又相当于一个既有加法标记又有覆盖标记的线段树了,方法是如果加遇上覆盖,那么直接把加加到覆盖上,如果覆盖遇到加,那么直接把加清0
维护的四个量一起更新,一定要注意用之前的x和y去更新xy和平方

那么40pts和70pts就是给正解想不全的人吧。。。

这道题在考场上拿到了满分,但其实不是刚开始思路就很清晰,是边写边发现可做的。因为加法标记和覆盖标记写得比较熟所以总体来说还是不错的。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 100005

const double inf=1e18;
int n,m;
double xiyi,xi,yi,xx;
double x[N],y[N],sum[N],sum2[N];
double sxy[N*4],sxx[N*4],sx[N*4],sy[N*4],ds[N*4],dt[N*4],cs[N*4],ct[N*4];

void update(int now)
{
    sxy[now]=sxy[now<<1]+sxy[now<<1|1];
    sx[now]=sx[now<<1]+sx[now<<1|1];
    sy[now]=sy[now<<1]+sy[now<<1|1];
    sxx[now]=sxx[now<<1]+sxx[now<<1|1];
}
void build(int now,int l,int r)
{
    int mid=(l+r)>>1;
    cs[now]=ct[now]=inf;
    if (l==r)
    {
        sxy[now]=x[l]*y[l];
        sx[now]=x[l];
        sy[now]=y[l];
        sxx[now]=x[l]*x[l];
        return;
    }
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    update(now);
}
void pushdown(int now,int l,int r,int mid)
{
    if (ds[now]||dt[now])
    {
        sxy[now<<1]+=dt[now]*sx[now<<1]+ds[now]*sy[now<<1]+ds[now]*dt[now]*(mid-l+1+0.0);
        sxx[now<<1]+=2*ds[now]*sx[now<<1]+ds[now]*ds[now]*(mid-l+1+0.0);
        sx[now<<1]+=ds[now]*(mid-l+1+0.0);
        sy[now<<1]+=dt[now]*(mid-l+1+0.0);
        if (cs[now<<1]!=inf||ct[now<<1]!=inf) cs[now<<1]+=ds[now],ct[now<<1]+=dt[now];
        else ds[now<<1]+=ds[now],dt[now<<1]+=dt[now];

        sxy[now<<1|1]+=dt[now]*sx[now<<1|1]+ds[now]*sy[now<<1|1]+ds[now]*dt[now]*(r-mid+0.0);
        sxx[now<<1|1]+=2*ds[now]*sx[now<<1|1]+ds[now]*ds[now]*(r-mid+0.0);
        sx[now<<1|1]+=ds[now]*(r-mid+0.0);
        sy[now<<1|1]+=dt[now]*(r-mid+0.0);
        if (cs[now<<1|1]!=inf||ct[now<<1|1]!=inf) cs[now<<1|1]+=ds[now],ct[now<<1|1]+=dt[now];
        else ds[now<<1|1]+=ds[now],dt[now<<1|1]+=dt[now];

        ds[now]=0;dt[now]=0;
    }
    if (cs[now]!=inf||ct[now]!=inf)
    {
        sxy[now<<1]=cs[now]*ct[now]*(mid-l+1+0.0)+(sum[mid]-sum[l-1])*(cs[now]+ct[now])+sum2[mid]-sum2[l-1];
        sxx[now<<1]=cs[now]*cs[now]*(mid-l+1+0.0)+2*cs[now]*(sum[mid]-sum[l-1])+sum2[mid]-sum2[l-1];
        sx[now<<1]=cs[now]*(mid-l+1+0.0)+sum[mid]-sum[l-1];
        sy[now<<1]=ct[now]*(mid-l+1+0.0)+sum[mid]-sum[l-1];
        ds[now<<1]=dt[now<<1]=0;
        cs[now<<1]=cs[now];ct[now<<1]=ct[now];

        sxy[now<<1|1]=cs[now]*ct[now]*(r-mid+0.0)+(sum[r]-sum[mid])*(cs[now]+ct[now])+sum2[r]-sum2[mid];
        sxx[now<<1|1]=cs[now]*cs[now]*(r-mid+0.0)+2*cs[now]*(sum[r]-sum[mid])+sum2[r]-sum2[mid];
        sx[now<<1|1]=cs[now]*(r-mid+0.0)+sum[r]-sum[mid];
        sy[now<<1|1]=ct[now]*(r-mid+0.0)+sum[r]-sum[mid];
        ds[now<<1|1]=dt[now<<1|1]=0;
        cs[now<<1|1]=cs[now];ct[now<<1|1]=ct[now];

        cs[now]=inf;ct[now]=inf;
    }
}
void change(int now,int l,int r,int lr,int rr,double s,double t,int opt)
{
    int mid=(l+r)>>1;
    if (l!=r) pushdown(now,l,r,mid);
    if (lr<=l&&r<=rr)
    {
        if (!opt)
        {
            sxy[now]+=t*sx[now]+s*sy[now]+s*t*(r-l+1+0.0);
            sxx[now]+=2*s*sx[now]+s*s*(r-l+1+0.0);
            sx[now]+=s*(r-l+1+0.0);
            sy[now]+=t*(r-l+1+0.0);
            if (cs[now]!=inf||ct[now]!=inf) cs[now]+=s,ct[now]+=t;
            else ds[now]+=s,dt[now]+=t;
        }
        else
        {
            sxy[now]=s*t*(r-l+1+0.0)+(sum[r]-sum[l-1])*(s+t)+sum2[r]-sum2[l-1];
            sxx[now]=s*s*(r-l+1+0.0)+2*s*(sum[r]-sum[l-1])+sum2[r]-sum2[l-1];
            sx[now]=s*(r-l+1+0.0)+sum[r]-sum[l-1];
            sy[now]=t*(r-l+1+0.0)+sum[r]-sum[l-1];
            ds[now]=dt[now]=0;
            cs[now]=s;ct[now]=t;
        }
        return;
    }
    if (lr<=mid) change(now<<1,l,mid,lr,rr,s,t,opt);
    if (mid+1<=rr) change(now<<1|1,mid+1,r,lr,rr,s,t,opt);
    update(now);
}
void query(int now,int l,int r,int lr,int rr)
{
    int mid=(l+r)>>1;
    if (l!=r) pushdown(now,l,r,mid);
    if (lr<=l&&r<=rr)
    {
        xiyi+=sxy[now];
        xi+=sx[now];
        yi+=sy[now];
        xx+=sxx[now];
        return;
    }
    if (lr<=mid) query(now<<1,l,mid,lr,rr);
    if (mid+1<=rr) query(now<<1|1,mid+1,r,lr,rr);
}
int main()
{
    freopen("relative.in","r",stdin);
    freopen("relative.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i) scanf("%lf",&x[i]);
    for (int i=1;i<=n;++i) scanf("%lf",&y[i]);
    for (int i=1;i<=n;++i) sum[i]=sum[i-1]+(double)i,sum2[i]=sum2[i-1]+(double)i*(double)i;
    build(1,1,n);
    while (m--)
    {
        int opt;scanf("%d",&opt);
        if (opt==1)
        {
            int l,r;scanf("%d%d",&l,&r);
            xiyi=xi=yi=xx=0;
            query(1,1,n,l,r);
            double xba=xi/(r-l+1+0.0);
            double yba=yi/(r-l+1+0.0);
            double up=xiyi-xba*yi-yba*xi+xba*yba*(r-l+1+0.0);
            double down=xx-2*xba*xi+xba*xba*(r-l+1+0.0);
            double ans=up/down;
            printf("%.10lf\n",ans);
        }
        else if (opt==2)
        {
            int l,r;scanf("%d%d",&l,&r);
            double s,t;scanf("%lf%lf",&s,&t);
            change(1,1,n,l,r,s,t,0);
        }
        else if (opt==3)
        {
            int l,r;scanf("%d%d",&l,&r);
            double s,t;scanf("%lf%lf",&s,&t);
            change(1,1,n,l,r,s,t,1);
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值