In mathematics you don't understand things, you just get used to them.

标签 number theory 下的文章

Description

Link.

求 $\sum\limits_{i=1}^n\sum\limits_{j=1}^n(i+j)^kf(\gcd(i,j))\gcd(i,j)$。

Solution

$$ \begin{aligned} \textbf{ANS}&=\sum_{i=1}^{n}\sum_{j=1}^{n}(i+j)^{k}\mu^{2}(\gcd(i,j))\gcd(i,j) \\ &=\sum_{d=1}^{n}\sum_{i=1}^{n}\sum_{j=1}^{n}(i+j)^{k}\mu^{2}(d)d[\gcd(i,j)=d] \\ &=\sum_{d=1}^{n}d^{k+1}\times\mu^{2}(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}(i+j)^{k}\sum_{h|i,h|j}\mu(h) \\ &=\sum_{d=1}^{n}d^{k+1}\times\mu^{2}(d)\sum_{h=1}^{\lfloor\frac{n}{d}\rfloor}\mu(h)\times h^{k}\times\sum_{i=1}^{\lfloor\frac{n}{dh}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{dh}\rfloor}(i+j)^{k} \\ &=\sum_{d=1}^{n}d^{k+1}\times\mu^{2}(d)\sum_{h=1}^{\lfloor\frac{n}{d}\rfloor}\mu(h)\times h^{k}\times\sum_{i=1}^{\lfloor\frac{n}{dh}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{dh}\rfloor}(i+j)^{k} \\ \end{aligned} \\ $$

前面两个和式里面显然能算,考虑怎么对于 $x$ 算 $\sum_{i=1}^{x}\sum_{j=1}^{x}(i+j)^{k}$。考虑对其差分:

$$ \begin{aligned} \left(\sum_{i=1}^{x+1}\sum_{j=1}^{x+1}(i+j)^{k}\right)-\left(\sum_{i=1}^{x}\sum_{j=1}^{x}(i+j)^{k}\right)&=\sum_{i=1}^{x}\sum_{j=1}^{x+1}(i+j)^{k}+\sum_{i=1}^{x+1}(x+1+i)^{k}-\sum_{i=1}^{x}\sum_{j=1}^{x}(i+j)^{k} \\ &=\sum_{i=1}^{x}\left(\sum_{j=1}^{x+1}(i+j)^{k}-\sum_{j=1}^{x}(i+j)^{k}\right)+\sum_{i=1}^{x+1}(x+1+i)^{k} \\ &=\sum_{i=1}^{x}(x+1+i)^{k}+\sum_{i=1}^{x+1}(x+1+i)^{k} \\ \end{aligned} $$

然后滚个前缀和就可以算了。

#include<bits/stdc++.h>
typedef long long LL;
const int MOD=998244353;
int norm( LL x ) {
    if( x<0 ) {
        x+=MOD;
    }
    if( x>=MOD ) {
        x%=MOD;
    }
    return x;
}
int n,k,ans;
int qpow( int bas,int fur ) {
    int res=1;
    while( fur ) {
        if( fur&1 ) {
            res=norm( LL( res )*bas );
        }
        bas=norm( LL( bas )*bas );
        fur>>=1;
    }
    return norm( res+MOD );
}
std::tuple<std::vector<int>,std::vector<int>> makePrime( int n ) {
    std::vector<int> prime,tag( n+1 ),mu( n+1 ),pw( n+1 );
    pw[0]=1;
    mu[1]=pw[1]=1;
    for( int i=2;i<=n;++i ) {
        if( !tag[i] ) {
            mu[i]=norm( -1 );
            prime.emplace_back( i );
            pw[i]=qpow( i,k );
        }
        for( int j=0;j<int( prime.size() ) && i*prime[j]<=n;++j ) {
            tag[i*prime[j]]=1;
            pw[i*prime[j]]=norm( LL( pw[i] )*pw[prime[j]] );
            if( i%prime[j]==0 ) {
                mu[i*prime[j]]=0;
                break;
            } else {
                mu[i*prime[j]]=norm( -mu[i] );
            }
        }
    }
    return std::tie( mu,pw );
}
int main() {
    LL tmp;
    scanf( "%d %lld",&n,&tmp );
    k=tmp%( MOD-1 );
    std::vector<int> mu,pw,prt( n+1 ),exprt( n+1 ),preSum( n+1 );
    // prt: i^(k+1)*mu^2(i)
    // exprt: mu(i)*i^k
    // preSum sum sum (i+j)^k
    std::tie( mu,pw )=makePrime( n<<1|1 );
    for( int i=1;i<=n;++i ) {
        prt[i]=norm( prt[i-1]+norm( LL( norm( LL( norm( LL( mu[i] )*mu[i] ) )*pw[i] ) )*i ) );
        exprt[i]=norm( exprt[i-1]+norm( LL( mu[i] )*pw[i] ) );
    }
    for( int i=1;i<=( n<<1 );++i ) {
        pw[i]=norm( pw[i]+pw[i-1] );
    }
    for( int i=1;i<=n;++i ) {
        preSum[i]=norm( norm( preSum[i-1]+norm( pw[i<<1]-pw[i] ) )+norm( pw[(i<<1)-1]-pw[i] ) );
    }
    for( int l=1,r;l<=n;l=r+1 ) {
        r=n/( n/l );
        int tmp=0;
        for( int exl=1,exr,m=n/l;exl<=m;exl=exr+1 ) {
            exr=m/( m/exl );
            tmp=norm( tmp+norm( LL( norm( exprt[exr]-exprt[exl-1] ) )*preSum[m/exl] ) );
        }
        ans=norm( ans+LL( norm( prt[r]-prt[l-1] ) )*tmp );
    }
    printf("%d\n",ans);
    return 0;
}

「ARC 116A」Odd vs Even

Link.

看 $n$ 有多少 $2$ 因子。

// Problem: A - Odd vs Even
// Contest: AtCoder - AtCoder Regular Contest 116
// URL: https://atcoder.jp/contests/arc116/tasks/arc116_a
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int make_two(LL n){int res=0; while((n&1ll)^1ll)    ++res,n>>=1; return res;}
int main()
{
    int T; scanf("%d",&T);
    while(T--)
    {
        LL n;
        scanf("%lld",&n);
        int one=make_two(n);
        if(one==1)    puts("Same");
        else if(one>1)    puts("Even");
        else    puts("Odd");
    }
    return 0;
}

「ARC 116B」Products of Min-Max

Link.

感觉这题很平庸很 B 题啊,不知道为什么那么多人说难……

首先排序,于是即算

$$ \left(\sum_{i=1}^{n}\sum_{j=i+1}^{n}a_{i}\times a_{j}\times2^{j-i-1}\right)+\left(\sum_{i=1}^{n}a_{i}^{2}\right) $$

也就是

$$ \sum_{i=1}^{n}a_{i}\sum_{j=i+1}^{n}a_{j}\times2^{j-i-1} \\ $$

$$ \sum_{j=i}^{n}a_{j}\times2^{j-i}=2\left(\sum_{j=i+1}^{n}a_{j}\times2^{j-i-1}\right)+a_{i} $$

于是直接 $\mathcal{O}(n)$ 算即可。智慧官方 editorial 指着这个式子说 $\mathcal{O}(n\log_{2}n)$ 不知道在干嘛。所以爆了个没什么用的标。

// Problem: B - Products of Min-Max
// Contest: AtCoder - AtCoder Regular Contest 116
// URL: https://atcoder.jp/contests/arc116/tasks/arc116_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD=998244353;
int n,a[200010],ans,sum;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)    scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;++i)
    {
        ans=(ans+LL(sum)*a[i]%MOD+LL(a[i])*a[i]%MOD)%MOD;
        sum=((LL(sum)<<1)%MOD+a[i])%MOD;
    }
    printf("%d\n",ans);
    return 0;
}

「ARC 116C」Multiple Sequences

Link.

我们只考虑每个序列的末尾,即 $A_{n}=1,\cdots,m$ 的情况。我们先来想暴力。

对于每一个 $A_{n}$ 的取值,记为 $d$,对 $d$ 分解质因数,$d=\prod_{i=1}^{k}p_{i}^{c_{i}}$。

然后对于这个 $d$,其可以构成的序列数即 $\prod_{i=1}^{k}\binom{n+c_{i}-1}{c_{i}}$。

考虑非暴力,就把素数筛出来就行了。

// Problem: C - Multiple Sequences
// Contest: AtCoder - AtCoder Regular Contest 116
// URL: https://atcoder.jp/contests/arc116/tasks/arc116_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD=998244353;
vector<int> makePrime(int n)
{
    vector<int> prime,tag(n+1);
    tag[1]=1;
    for(int i=2;i<=n;++i)
    {
        if(!tag[i])    prime.push_back(i);
        for(int j=0;j<int(prime.size()) && i*prime[j]<=n;++j)
        {
            tag[i*prime[j]]=1;
            if(i%prime[j]==0)    break;
        }
    }
    return prime;
}
int n,m,ans;
vector<int> fac,ifac;
void exGCD(int one,int ano,int &x,int &y)
{
    if(ano==0)    x=1,y=0;
    else    exGCD(ano,one%ano,y,x),y-=(one/ano)*x;
}
int getInv(int val){int res,w; exGCD(val,MOD,res,w); return (res+MOD)%MOD;}
int C(int n,int k){return n<k?0:LL(fac[n])*ifac[k]%MOD*ifac[n-k]%MOD;}
int main()
{
    scanf("%d %d",&n,&m);
    vector<int> prime=makePrime(200100);
    fac.push_back(1);
    for(int i=1;i<=200100;++i)    fac.push_back(LL(fac.back())*i%MOD);
    for(int i=0;i<=200100;++i)    ifac.push_back(getInv(fac[i]));
    for(int i=1;i<=m;++i)
    {
        int curm=i,tmp=1;
        for(int j=0;j<int(prime.size()) && prime[j]<=curm;++j)
        {
            if(curm%prime[j]==0)
            {
                int ups=0;
                while(curm%prime[j]==0)    curm/=prime[j],++ups;
                tmp=LL(tmp)*C(n+ups-1,ups)%MOD;
            }
        }
        ans=(ans+tmp)%MOD;
    }
    printf("%d\n",ans);
    return 0;
}

「ARC 116D」I Wanna Win The Game

Link.

这题的 DP 感觉略有点难往这方面想。

考虑这题的限制最强的是 $\texttt{XOR}$ 和为 $0$ 以及和恰为 $m$。可以大概猜测此题与 $n$ 关系不大。

那么我们可以考虑从最低位开始做这个题。

设 $f_{i}$ 为构造出来序列的和为 $i$ 且 $\texttt{XOR}$ 和为 $0$ 的数量。

Oops, something went wrong.

「ARC 116E」Spread of Information

Link.

Oops, something went wrong.

「ARC 116F」Deque Game

Link.

Oops, something went wrong.

「ABC 193A」Discount

Link.

略。

#include<cstdio>
int main()
{
    int a,b;
    scanf("%d %d",&a,&b);
    printf("%.2f\n",(1.0-(double)b/(double)a)*100.0);
    return 0;
}

「ABC 193B」Play Snuke

Link.

排序。

#include<cstdio>
#include<algorithm>
using namespace std;
struct node
{
    int tim,pay,ps;
}nodes[100010];
bool cmp(node one,node ano)
{
    return one.pay<ano.pay;
}
int ans=-1;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)    scanf("%d %d %d",&nodes[i].tim,&nodes[i].pay,&nodes[i].ps);
    sort(nodes+1,nodes+n+1,cmp);
    for(int i=1;i<=n;++i)
    {
        if(((int)((double)nodes[i].tim-0.5)+1)<nodes[i].ps)
        {
            ans=nodes[i].pay;
            break;
        }
    }
    printf("%d\n",ans);
    return 0;
}

「ABC 193C」Unexpressed

Link.

可以容斥,也可以暴力枚举 std::set 去重。

#include<set>
#include<iostream>
#define int long long
using namespace std;
set<int> app;
signed main()
{
    int n,ians=0;
    cin>>n;
    for(int i=2;i*i<=n;++i)
    {
        for(int j=i*i;j<=n;j*=i)
        {
            if(!app.count(j))
            {
                ++ians;
                app.insert(j);
            }
        }
    }
    cout<<n-ians;
    return 0;
}

「ABC 193D」Poker

Link.

开个答案+单位贡献的结构体,然后模拟。

#include<iostream>
#include<iomanip>
using namespace std;
#define int long long
#define ID(c) ((c)-'0')
int k,num[20];
char s[20],t[20];
struct node
{
    int iths[20],sum,c[20];
    int spow(int fur)
    {
        int res=1;
        for(int i=1;i<=fur;++i)    res*=10;
        return res;
    }
    void getscor(char x[])
    {
        for(int i=1;i<=4;++i)    ++c[ID(x[i])];
        for(int i=1;i<=9;++i)
        {
            iths[i]=i*spow(c[i]);
            sum+=iths[i];
        }
    }
    void Op(int pos,int delta)
    {
        c[pos]+=delta;
        sum-=iths[pos];
        if(~delta)    iths[pos]*=10;
        else    iths[pos]/=10;
        sum+=iths[pos];
    }
}tak,aok;
signed main()
{
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    cin>>k>>(s+1)>>(t+1);
    for(int i=1;i<=9;++i)    num[i]=k;
    for(int i=1;i<=4;++i)    --num[ID(s[i])],--num[ID(t[i])];
    tak.getscor(s);
    aok.getscor(t);
    int winans=0,allans=0;
    for(int i=1;i<=9;++i)
    {
        for(int j=1;j<=9;++j)
        {
            tak.Op(i,1);
            aok.Op(j,1);
            if(tak.sum>aok.sum)
            {
                if(i^j)    winans+=num[i]*num[j];
                else    winans+=num[i]*(num[j]-1);
            }
            tak.Op(i,-1);
            aok.Op(j,-1);
        }
    }
    for(int i=1;i<=9;++i)
    {
        for(int j=1;j<=9;++j)
        {
            if(i^j)    allans+=num[i]*num[j];
            else    allans+=num[i]*(num[j]-1);
        }
    }
    cout<<fixed<<setprecision(6)<<(double)winans/(double)allans<<endl;
    return 0;
}

「ABC 193E」Oversleeping

Link.

开始想到计算几何去了,打了很久。

实际上因为 $500$ 的范围,你可以直接枚举余数然后 exCRT 合并。

#include<cstdio>
#include<climits>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL INF=LONG_LONG_MAX;
namespace NumbTheo
{
    LL ftimes(LL bas,LL fur,LL mod)
    {
        LL res=0;
        while(fur)
        {
            if(fur&1)    res=(res+bas)%mod;
            bas=(bas+bas)%mod,fur>>=1;
        }
        return res;
    }
    LL exGCD(LL one,LL ano,LL &x,LL &y)
    {
        if(ano==0)    return (x=1,y=0,one);
        else
        {
            LL tmp=exGCD(ano,one%ano,y,x);
            y-=(one/ano)*x;
            return tmp;
        }
    }
    LL exCRT(LL n,LL one[],LL ano[])
    {
        LL x,y,res=one[1],M=ano[1];
        for(int i=2;i<=n;++i)
        {
            LL a=M,b=ano[i],c=(one[i]-res%b+b)%b,tmp=exGCD(a,b,x,y),d=b/tmp;
            if(c%tmp)    return -1;
            x=ftimes(x,c/tmp,d);
            res+=x*M,M*=d,res=(res%M+M)%M;
        }
        return (res%M+M)%M;
    }
};
int t;
LL one[10],ano[10],ans;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        LL X,Y,P,Q;
        scanf("%lld %lld %lld %lld",&X,&Y,&P,&Q);
        ans=INF;
        for(LL i=X;i<X+Y;++i)
        {
            for(int j=P;j<P+Q;++j)
            {
                using namespace NumbTheo;
                one[1]=i,ano[1]=((X+Y)<<1),one[2]=j,ano[2]=P+Q;
                LL tmp=exCRT(2,one,ano);
                if(~tmp)    ans=min(ans,tmp);
            }
        }
        if(ans==INF)    printf("infinity\n");
        else    printf("%lld\n",ans);
    }
    return 0;
}

「ABC 193F」Zebraness

Link.

把 $i+j$ 为奇数的地方反转一下,然后连边求最小割。

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
#define getID(x,y) (((x)-1)*n+(y))
namespace MaxFlow
{
    queue<int> q;
    const LL INF=1e9;
    int S,T,head[10010],Cur[10010],cntot=1,all,vis[10010];
    LL dep[10010];
    struct Edge
    {
        int to,nxt;
        LL c;
        Edge(int A=0,int B=0,LL C=0){to=A,nxt=B,c=C;}
    }as[500010];
    bool bfs()
    {
        for(int i=1;i<=all;++i)    vis[i]=0,dep[i]=INF;
        q.push(S),dep[S]=0,vis[S]=1;
        while(!q.empty())
        {
            int now=q.front();
            q.pop(),vis[now]=0;
            for(int i=head[now];i;i=as[i].nxt)
            {
                int y=as[i].to;
                LL c=as[i].c;
                if(c&&dep[y]>dep[now]+1)
                {
                    dep[y]=dep[now]+1;
                    if(!vis[y])    q.push(y),vis[y]=1;
                }
            }
        }
        return dep[T]<INF;
    }
    LL dfs(int x,LL lav)
    {
        if(x==T)    return lav;
        LL used=0;
        vis[x]=1;
        for(int &i=Cur[x];i;i=as[i].nxt)
        {
            int y=as[i].to;
            LL c=as[i].c;
            if(c&&dep[y]==dep[x]+1&&!vis[y])
            {
                LL tmp=dfs(y,min(lav-used,c));
                as[i].c-=tmp,as[i^1].c+=tmp,used+=tmp;
                if(lav==used)    break;
            }
        }
        if(used<lav)    dep[x]=INF;
        vis[x]=0;
        return used;
    }
    LL Dinic()
    {
        LL res=0;
        while(bfs())
        {
            for(int i=1;i<=all;++i)    vis[i]=0,Cur[i]=head[i];
            res+=dfs(S,INF);
        }
        return res;
    }
}using namespace MaxFlow;
int n;
int rop()
{
    char res=getchar();
    while((res^'B')&&(res^'W')&&(res^'?'))    res=getchar();
    if(res=='?')    return -1;
    else if(res=='B')    return 1;
    else    return 0;
}
void addEdge(int one,int ano,int lav)
{
    as[++cntot]=Edge(ano,head[one],lav);
    head[one]=cntot;
    as[++cntot]=Edge(one,head[ano],0);
    head[ano]=cntot;
}
int main()
{
    scanf("%d",&n),all=n*n;
    S=(++all),T=(++all);
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=n;++j)
        {
            int x=rop();
            if(~x)
            {
                if((i+j)&1)    x^=1;
                if(x)    addEdge(S,getID(i,j),INF);
                else    addEdge(getID(i,j),T,INF);
            }
        }
    }
    for(int i=1;i<n;++i)
    {
        for(int j=1;j<=n;++j)    addEdge(getID(i,j),getID(i+1,j),1),addEdge(getID(i+1,j),getID(i,j),1);
    }
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<n;++j)    addEdge(getID(i,j),getID(i,j+1),1),addEdge(getID(i,j+1),getID(i,j),1);
    }
    printf("%lld\n",2*n*(n-1)-Dinic());
    return 0;
}

「ARC 113A」A*B*C

Link.

就是算 $\sum_{i=1}^{k}\sum_{j=1}^{\lfloor\frac{k}{i}\rfloor}\lfloor\frac{k}{j\times j}\rfloor$。

直接调和级数。

#include<cstdio>
long long k;
int main()
{
    scanf("%lld",&k);
    long long ans=0;
    for(long long i=1;i<=k;++i)
    {
        for(long long j=1;j<=k/i;++j)    ans+=(k/i/j);
    }
    printf("%lld\n",ans);
    return 0;
}

「ARC 113B」A^B^C

Link.

扩展欧拉定理裸题,$A^{B^{C}}\bmod10=A^{(B^{C}\bmod\varphi(10))+\varphi(10)}\bmod10$。

#include<cstdio>
long long getphi(long long x)
{
    long long res=x;
    for(long long i=2;i*i<=x;++i)
    {
        if(x%i==0)
        {
            res=res/i*(i-1);
            while(x%i==0)    x/=i;
        }
    }
    if(x>1)    res=res/x*(x-1);
    return res;
}
long long cqpow(long long bas,long long fur,long long mod)
{
    long long res=1;
    while(fur)
    {
        if(fur&1)    res=res*bas%mod;
        bas=bas*bas%mod;
        fur>>=1;
    }
    return res;
}
long long a,b,c;
int main()
{
    scanf("%lld %lld %lld",&a,&b,&c);
    printf("%lld\n",cqpow(a,cqpow(b,c,getphi(10))+getphi(10),10));
    return 0;
}

「ARC 113C」String Invasion

Link.

正序枚举 $i\in[1,n]$,如果满足条件,那么后面的字符串都可以执行操作,则 $ans:=ans+n-i$。

当然,由于后面可能存在一个字符就是 $s_{i}$,所以要记录当前操作的字符,特判 $ans:=ans-1$。

#include<cstdio>
#include<cstring>
int n;
long long ans;
char s[200010];
int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    char las=0;
    for(int i=1;i<=n;++i)
    {
        if(i!=n&&s[i]==s[i+1]&&s[i]!=s[i+2]&&s[i]!=las)    ans+=n-i,las=s[i];
        else if(s[i]==las)    --ans;
    }
    printf("%lld\n",ans);
    return 0;
}

「ARC 113D」Sky Reflector

Link.

显然只要 $\forall i\in[1,m],b_{i}\ge a_{\max}$ 即可,那么枚举 $i\in[1,k]=a_{\max}$,有:

$$ ans=\sum_{i=1}^{k}(i^{n}-(i-1)^{n})\times(k-i+1)^{m}\bmod998244353 $$

#include<cstdio>
const int mod=998244353;
long long cqpow(long long bas,int fur)
{
    long long res=1;
    while(fur)
    {
        if(fur&1)    res=res*bas%mod;
        bas=bas*bas%mod;
        fur>>=1;
    }
    return res;
}
int n,m,k;
long long ans;
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    if(n==1)    ans=cqpow(k,m);
    else if(m==1)    ans=cqpow(k,n);
    else
    {
        for(int i=1;i<=k;++i)    ans=(ans+((cqpow(i,n)-cqpow(i-1,n)+mod)%mod)*cqpow(k-i+1,m)%mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

「ARC 113E」Rvom and Rsrev

Link.

「ARC 113F」Social Distance

Link.

「CF 1485A」Add and Divide

Link.

贪心。枚举 $[b,b+\log_{2}\text{range}]$ 然后取个 $\min$。

#include<cstdio>
#include<algorithm>
using namespace std;
int t,a,b,ans;
int search(int bas)
{
    if(bas>1)
    {
        int tmp=a,res=0;
        while(tmp>0)
        {
            tmp/=bas;
            res++;
        }
        return res;
    }
    else    return 1e9;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&a,&b);
        if(a==b)    printf("%d\n",2);
        else if(a<b)    printf("%d\n",1);
        else
        {
            ans=1e9;
            for(int i=b;i<=b+233;++i)    ans=min(ans,search(i)+i-b);
            printf("%d\n",ans);
        }
    }
    return 0;
}

「CF 1485B」Replace and Keep Sorted

Link.

每个元素都可以上下摇摆于是预处理前缀差分和和后缀差分和(因为是 strictly increasing 所以要减 $1$)即可。

#include<cstdio>
int n,m,k,a[100010],fro[100010],rea[100010];
void pre()
{
    for(int i=1;i<=n;++i)    fro[i]=a[i]-a[i-1]-1;
    for(int i=n;i>=1;--i)    rea[i]=a[i+1]-a[i]-1;
    for(int i=1;i<=n;++i)    fro[i]+=fro[i-1];
    for(int i=n;i>=1;--i)    rea[i]+=rea[i+1];
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=n;++i)    scanf("%d",&a[i]);
    pre();
    while(m--)
    {
        int l,r;
        scanf("%d %d",&l,&r);
        printf("%d\n",k-a[r]+a[l]-1+fro[r]-fro[l]+rea[l]-rea[r]);
    }
    return 0;
}

「CF 1485C」Floor and Mod

Link.

$$ a\bmod b=\lfloor\frac{a}{b}\rfloor=k \\ \rightarrow a=kb+k\rightarrow a=(b+1)k\rightarrow k=\frac{a}{b+1} \\ k<b\rightarrow k^{2}<k(b+1)=a\le x\rightarrow 1\le k\le\sqrt{x} \\ 1\le a\le x\rightarrow 1\le(b+1)k\le x\rightarrow1\le b\le\frac{x}{k}-1 \\ \rightarrow\text{ans}=\sum_{k=1}^{\sqrt{x}}\max(0,\min(y,\frac{x}{k}-1)-k) $$

#include<cstdio>
#include<algorithm>
using namespace std;
const long long zero=0ll;
long long t,x,y,ans;
int main()
{
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld %lld",&x,&y);
        ans=0;
        for(long long i=1;i*i<=x;++i)    ans+=max(zero,min(y,x/i-1)-i);
        printf("%lld\n",ans);
    }
    return 0;
}

「CF 1485D」Multiples and Power Differences

Link.

  • $(i+j)\bmod 2=1$:$b_{i,j}=\text{lcm}(1,\cdots,16)$。
  • $(i+j)\bmod 2=0$:$b_{i,j}=\text{lcm}(1,\cdots,16)+a_{i,j}^{4}$。

#include<cstdio>
int n,m,x;
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=m;++j)
        {
            scanf("%d",&x);
            if((i+j)&1)    printf("%d ",720720);
            else    printf("%d ",720720+x*x*x*x);
        }
        printf("\n");
    }
    return 0;
}

「CF 1485E」Move and Swap

Link.

blue 因为就是一直往下跑,所以一次操作在哪里不影响。

于是设 $f_{u}$ 为操作完毕后 red 跑到 $u$ 的 maximum value。

  • $v\in\text{son}(u)$ 为 red:此时没发生 swapping,$f_{u}=f_{v}+|a_{u}-a_{v}|$。
  • $v\in\text{son}(u)$ 为 blue:此时发生了 swapping,那么枚举 $v$ 的同层结点 $anov$,$f_{u}=f_{anov}+|a_{u}-a_{anov}|$。

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
const long long INF=1e18;
vector<int> e[200010],same[200010];
int t,n,dep[200010],fa[200010],leaf;
long long a[200010],f[200010];
void dfs(int x,int las)
{
    dep[x]=dep[las]+1;
    fa[x]=las;
    leaf=max(leaf,dep[x]);
    for(int i=0;i<e[x].size();++i)
    {
        int y=e[x][i];
        if(y^las)    dfs(y,x);
    }
}
void DP(int d)
{
    for(int i=d;i>1;--i)
    {
        long long mn=INF,mx=-INF,one=-INF,ano=-INF;
        for(int j=0;j<same[i].size();++j)
        {
            mn=min(mn,a[same[i][j]]);
            mx=max(mx,a[same[i][j]]);
        }
        for(int j=0;j<same[i].size();++j)    f[fa[same[i][j]]]=max(f[fa[same[i][j]]],max(a[same[i][j]]-mn,mx-a[same[i][j]])+f[same[i][j]]);
        for(int j=0;j<same[i].size();++j)
        {
            one=max(one,f[same[i][j]]+a[same[i][j]]);
            ano=max(ano,f[same[i][j]]-a[same[i][j]]);
        }
        for(int j=0;j<same[i].size();++j)    f[fa[same[i][j]]]=max(f[fa[same[i][j]]],max(one-a[same[i][j]],ano+a[same[i][j]]));
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=2;i<=n;++i)
        {
            int x;
            scanf("%d",&x);
            e[x].push_back(i);
            e[i].push_back(x);
        }
        for(int i=2;i<=n;++i)    scanf("%d",&a[i]);
        dfs(1,0);
        for(int i=1;i<=n;++i)    same[dep[i]].push_back(i);
        DP(leaf);
        printf("%lld\n",f[1]);
        for(int i=1;i<=n;++i)
        {
            f[i]=dep[i]=fa[i]=0;
            same[i].clear();
            e[i].clear();
        }
        leaf=0;
    }
    return 0;
}

「CF 1485F」Copy or Prefix Sum

Link.