Comet OJ - Contest #8

Preface

最近板刷比赛都跟着bzt神仙的节奏来啊,看到他在打Comet OJ 所以我也来打了

看比赛榜就知道这一次前5题都很多人过但F无人AC,bzt说正解是LCT优化长链剖分,我立刻就不想写了QAQ


A 杀手皇后

SB题不解释

#include<iostream>
#include<string>
using namespace std;
int n; string s,ans;
int main()
{
    ios::sync_with_stdio(0); cin>>n;
    for (register int i=1;i<=n;++i) cin>>s,(ans==""||s<ans)&&(ans=s,0);
    return cout<<ans,0;
}

B 支援城市

把平方拆了发现我们只需要维护\(\sum_{i=1}^n w_i^2\)\(\sum_{i=1}^n w_i\)就可以对于每一个\(xO(1)\)计算了

#include<cstdio>
using namespace std;
const int N=100005;
int n,a[N]; long long sum,psum;
int main()
{
    register int i; for (scanf("%d",&n),i=1;i<=n;++i)
    scanf("%d",&a[i]),sum+=a[i],psum+=1LL*a[i]*a[i];
    for (i=1;i<=n;++i) printf("%lld ",psum+1LL*n*a[i]*a[i]-2LL*sum*a[i]);
    return 0;
}

C

首先发现符文石无论怎样合并最后的答案都是一样的,因此我们先把从左到右的答案全算出来

然后考虑可以精炼一个区间,那么我们发现这个区间的两端都乘上了一个\(k-1\)的系数,然后中间的数乘上了\(k^2-1\)的系数

那我们直接DP设\(f_i\)为包含\(i\)的答案,每次按\(i\)为左右中三个位置更新答案即可

#include<cstdio>
#include<iostream>
#define RI register int
using namespace std;
const int N=100005;
int n,k,a[N],b[N]; long long f[N],ret,dlt;
int main()
{
    RI i; for (scanf("%d%d",&n,&k),i=1;i<=n;++i)
    {
        scanf("%d%d",&a[i],&b[i]); ret+=b[i-1]*a[i];
        dlt=min(dlt,f[i-1]+1LL*(k-1)*b[i-1]*a[i]);
        f[i]=min(f[i],min(1LL*(k-1)*b[i-1]*a[i],f[i-1]+1LL*(k*k-1)*b[i-1]*a[i]));
    }
    return printf("%lld",ret+dlt),0;
}

D 菜菜种菜

bzt神仙刚开始用sort然后T掉了,所以我就学乖了没有sort……

首先我们考虑对于每一块菜地预处理出编号比它小的最大值\(l_i\)以及编号比它大的最小值\(r_i\),那么一个区间\([L,R]\)合法当且仅当\(l_i<L\)\(R<r_i\)

所以现在我们相当于要计算\(\sum_{i=L}^R [l_i<L\le R<r_i]s_i\),我们稍加转化就变成\(\sum_{i=1}^n[l_i+1\le L\le i\le R\le r_i-1]s_i\)

考虑我们按序枚举\(L\),每次再将\(L-1\)位置上的所有\(l_i=L-1\)\(i\)\([i,r_i-1]\)区间加上\(s_i\),然后将\(i=L-1\)\([i,r_i-1]\)\(s_i\)扣去,再查询\(R\)上的值即为答案

树状数组+vector即可维护上述过程,复杂度\(O(n\log n)\)(树状数组的\(\log\)快到难以想象)

#include<cstdio>
#include<cctype>
#include<utility>
#include<vector>
#include<iostream>
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
const int N=1e6+5;
typedef pair <int,int> pi;
typedef vector <pi>::iterator VP;
int n,m,q,l[N],r[N],x,y,a[N],ans[N],mx; long long ret; vector <pi> et[N],ques[N];
class FileInputOutput
{
    private:
        static const int S=1<<21;
        #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
        #define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
        char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[15];
    public:
        Tp inline void read(T& x)
        {
            x=0; char ch; while (!isdigit(ch=tc()));
            while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
        }
        Tp inline void write(T x)
        {
            RI ptop=0; while (pt[++ptop]=x%10,x/=10);
            while (ptop) pc(pt[ptop--]+48); pc('\n');
        }
        #undef tc
        #undef pc
}F;
class Tree_Array
{
    private:
        int bit[N];
        #define lowbit(x) x&-x
        inline void add(RI x,CI mv)
        {
            for (;x<=n;x+=lowbit(x)) bit[x]+=mv;
        }
    public:
        inline void modify(CI l,CI r,CI mv)
        {
            if (l>r) return; add(l,mv); add(r+1,-mv);
        }
        inline int query(RI x,int ret=0)
        {
            for (;x;x-=lowbit(x)) ret+=bit[x]; return ret;
        }
        #undef lowbit
}BIT;
int main()
{
    //freopen("D.in","r",stdin); freopen("D.out","w",stdout);
    RI i; for (F.read(n),F.read(m),F.read(q),i=1;i<=n;++i) F.read(a[i]),r[i]=n+1;
    for (i=1;i<=m;++i) F.read(x),F.read(y),y<x&&(l[x]=max(l[x],y)),y>x&&(r[x]=min(r[x],y));
    for (i=1;i<=q;++i) F.read(x),F.read(y),ques[x].pb(mp(y,i)),mx=max(mx,y);
    for (i=1;i<=n;++i) et[l[i]].pb(mp(r[i],i)); for (i=1;i<=mx;++i)
    {
        for (VP it=et[i-1].begin();it!=et[i-1].end();++it)
        BIT.modify(it->se,it->fi-1,a[it->se]); BIT.modify(i-1,r[i-1]-1,-a[i-1]);
        for (VP it=ques[i].begin();it!=ques[i].end();++it) ans[it->se]=BIT.query(it->fi);
    }
    for (i=1;i<=q;++i) ret^=1LL*i*ans[i]; return printf("%lld",ret),0;
}

E 神奇函数

神仙数论题,首先我们冷静分析一下\(f(x)\)的本质就是求\(x\)在分解质因数之后将每个质因子的次数除以\(2\)(下取整)

这个很好理解,我们观察第二个式子,发现就是一个不停提出质因数的过程

所以我们发现\(f(x)\)的值域就是根号级别的,我们可以枚举\(f(x)\)的值,然后算出有多少个数的值为这个

实际上,我们可以得出关于答案的这样一个式子:

\[ans=\sum_{i=1}^{\sqrt n} i\cdot g(\frac{n}{i^2})\]

其中\(g(x)\)表示\([1,x]\)内不含有平方因子的数的个数

为什么是这个函数呢,很简单,因为一旦它有了平方因子那个因子就可以被提出来,所以值就不是当前的值了

考虑\(g(x)=\sum_{i=1}^x \mu(i)^2\),运用一下经典容斥就会发现它其实是\(\sum_{i=1}^{\sqrt{x}}\mu(i)\cdot \lfloor\frac{n}{i^2}\rfloor\)

这样这题大致就可以做了,我们对于枚举答案的一层和计算\(g(x)\)的时候都除法分块一下,复杂度就是\(O(n^{\frac{2}{3}})\)

如果直接这样写就会T掉好多点,因此我们还要预处理一下\(\le 10^7\)\(g(x)\),直接回答即可

#include<cstdio>
#include<cmath>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
typedef long long LL;
const int N=1e7;
int t,prime[N+5],cnt,mu[N+5],g[N+5]; bool vis[N+5]; LL n,ans;
#define Pi prime[j]
inline void init(CI n)
{
    RI i,j; for (mu[1]=vis[1]=1,i=2;i<=n;++i)
    {
        if (!vis[i]) prime[++cnt]=i,mu[i]=-1;
        for (j=1;j<=cnt&&i*Pi<=n;++j)
        {
            vis[i*Pi]=1; if (i%Pi) mu[i*Pi]=-mu[i]; else break;
        }
    }
    for (i=1;i<=n;++i) g[i]=g[i-1]+mu[i]*mu[i];
    for (i=1;i<=n;++i) mu[i]+=mu[i-1];
}
#undef Pi
inline LL G(const LL& x)
{
    if (x<=N) return g[x];
    int lim=sqrt(x); LL ret=0; for (RI l=1,r;l<=lim;l=r+1)
    r=min(lim,(int)sqrt(x/(x/(1LL*l*l)))),ret+=1LL*(mu[r]-mu[l-1])*(x/(1LL*l*l));
    return ret;
}
inline LL sum(CI l,CI r)
{
    return 1LL*(l+r)*(r-l+1)>>1LL;
}
int main()
{
    //freopen("E.in","r",stdin); freopen("E.out","w",stdout);
    for (init(N),scanf("%d",&t);t;--t)
    {
        scanf("%lld",&n); int lim=sqrt(n); ans=0; for (RI l=1,r;l<=lim;l=r+1)
        r=min(lim,(int)sqrt(n/(n/(1LL*l*l)))),ans+=1LL*sum(l,r)*G(n/(1LL*l*l));
        printf("%lld\n",ans);
    }
    return 0;
}

F 黄金体验

LCT优化长链剖分,谁爱写谁写

咕咕咕


Postscript

比赛体验还好,算是混了个平均水平吧(感谢B指导和陈指导的指导)

猜你喜欢

转载自www.cnblogs.com/cjjsb/p/11349640.html