8.19NOIP Day5模拟赛

T1

观察到连边构成了一大堆互不相同的链,考虑算出每一种长度链的数量

\(a=1\) 时单独讨论,其他情况链长都不会超过 \(log\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
    int n,a,b;
    scanf("%lld%lld%lld",&n,&a,&b);
    if(a==1&&b<=sqrt(n)){
        int ans=0;
        for(int i=1;i<=b;i++)ans+=(n-i)/b/2+1;
        printf("%lld\n",ans);
        return 0;
    }
    int flag=0,summ=0,p=1,now=0,ans=0,add=0;
    while(summ+p<=n){
        p=p*a;
        summ*=a;
        summ+=b;
        now++;
    }
    for(int i=now;i;i--){
        p/=a;
        summ-=b;
        summ/=a;
        int to=(n-summ)/p;
        ans+=(to-flag-add)*((i+1)/2);
        add+=to-flag-add;
        flag=to;
    }
    printf("%lld\n",ans);
    return 0;
}

T2

朴素的DP就是记录下最后三位的大小,但是我们可以把它优化成后缀gcd,这样的话每一个后缀gcd都是前一个的倍数,状态大量减少,然后使用滚动数组优化空间

#include<bits/stdc++.h>
#define int long long
#define N 205
#define mod 1000000007
#define M 105
using namespace std;
int L[N],R[N],f[N][N],dp[2][M][M][M];
signed main(){
    int n,m=0;
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)scanf("%lld%lld",&L[i],&R[i]);
    for(int i=1;i<=n;i++)m=max(m,R[i]);
    for(int i=1;i<=m;i++)for(int j=1;j<=m;j++)f[i][j]=__gcd(i,j);
    for(int i=L[1];i<=R[1];i++)for(int j=L[2];j<=R[2];j++)for(int k=L[3];k<=R[3];k++)dp[1][f[i][f[j][k]]][f[j][k]][k]++;
    for(int i=4;i<=n;i++){
        int u=(i&1),v=(u^1);
        memset(dp[u],0,sizeof(dp[u]));
        for(int j=L[i];j<=R[i];j++)for(int k=1;k<=m;k++)for(int l=k;l<=m;l+=k)for(int h=l;h<=m;h+=l)dp[u][f[l][j]][f[h][j]][j]=(dp[u][f[l][j]][f[h][j]][j]+dp[v][k][l][h]*(f[j][k]+1)%mod)%mod;
    }
    int ans=0;
    for(int i=1;i<=m;i++)for(int j=i;j<=m;j+=i)for(int k=j;k<=m;k+=j)ans=(ans+dp[n&1][i][j][k])%mod;
    printf("%lld\n",ans);
    return 0;
}

T3

我们对于每一个点 \(i\) 暴力维护从它出发,终点 \(\le j\) 的数量,然后进行无限分讨。

#include<bits/stdc++.h>
#define N 505
using namespace std;
int s[N][N],y[N][N],n,q;
signed main(){
    int op,u,v,summ=0,a,b;
    scanf("%d%d",&n,&q);
    while(q--){
        scanf("%d%d%d",&op,&u,&v);
        if(u>v)swap(u,v);
        if(op==1){
            for(int i=v;i<=n;i++){
                y[u][i]++;
                s[u][i]+=v-u;
            }
            summ+=v-u;
        }
        else{
            int now=0,mid=u+(v-u+1)/2;
            for(int i=1;i<=u;i++){
                now+=(y[i][n]-y[i][v])*(v-u);
                a=y[i][v]-y[i][mid-1];
                b=s[i][v]-s[i][mid-1];
                now+=b-(a*(v-i)-b+a*(u-i));
            }
            for(int i=u+1;i<mid;i++){
                now+=(y[i][n]-y[i][v])*((v-i)-(i-u));
                int to=i+i-u+(v-(i+i-u)+1)/2;
                a=y[i][v]-y[i][to-1];
                b=s[i][v]-s[i][to-1];
                now+=b-(a*(v-u)-b);
            }
            printf("%d\n",summ-now);
        }
    }
    return 0;
}
posted @ 2025-08-19 20:39  Igunareo  阅读(14)  评论(0)    收藏  举报