CSP模拟20

CSP模拟20

T1 跳火山 luogu P3579

整数分块做 \((a-1)/r<b/r\) 的符合条件,直接跳到最大的 \(r\) ,复杂度 \(O(n\sqrt(n))\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int a,b,c,d,ans;
void work(){
    scanf("%d%d%d%d",&a,&b,&c,&d);
    for(int i=1,r=0;i<=min(b,d);i=r+1){
        r=(int)min(b/(b/i),d/(d/i));
        if((a-1)/r<b/r&&(c-1)/r<d/r) ans=r;
    }
    printf("%d\n",ans);
}
int main(){
    freopen("melina.in","r",stdin);
    freopen("melina.out","w",stdout);

    int n;
    scanf("%d",&n);
    while(n--)work();

    fclose(stdin);
    fclose(stdout);
    return 0;
}

T2 赞美太阳 luogu P3502

求出添加一个串的代价,类似于floyed,用矩阵快速幂优化。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define int long long
int n,m,siz[210],nex[210][100010];
char s[210][100010];
struct nod{
    int dis[210][210];
}a,ans;
nod operator * (nod x,nod y){
    nod z;
    for(int i=0;i<=n;i++){
        for(int j=0;j<=n;j++){
            z.dis[i][j]=1e15;
        }
    }
    for(int k=0;k<=n;k++){
        for(int i=0;i<=n;i++){
            for(int j=0;j<=n;j++){
                z.dis[i][j]=min(z.dis[i][j],x.dis[i][k]+y.dis[k][j]);
            }
        }
    }
    return z;
}
signed main(){
    freopen("sunshine.in","r",stdin);
    freopen("sunshine.out","w",stdout);

    scanf("%lld%lld",&n,&m);
    for(int i=0;i<=n;i++){
        for(int j=0;j<=n;j++) a.dis[i][j]=1e15;
    }
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]+1);
        siz[i]=strlen(s[i]+1);
        a.dis[0][i]=siz[i];
    }
    for(int i=1;i<=n;i++){
        int j=0;
        for(int tot=2;tot<=siz[i];tot++){
            while(j>0&&s[i][j+1]!=s[i][tot]) j=nex[i][j];
            if(s[i][j+1]==s[i][tot]) j++;
            nex[i][tot]=j;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int k=0;
            for(int tot=2;tot<=siz[i];tot++){
                while(k>0&&s[j][k+1]!=s[i][tot]) k=nex[j][k];
                if(s[j][k+1]==s[i][tot]) k++;
                if(tot==siz[i]) a.dis[i][j]=siz[j]-k;
            }
        }
    }
    m--;
    ans=a;
    while(m){
        if(m&1){
            ans=ans*a;
        }
        a=a*a;
        m>>=1;
    }
    int an=1e15;
    for(int i=1;i<=n;i++){
        an=min(an,ans.dis[0][i]);
    }
    printf("%lld",an);

    fclose(stdin);
    fclose(stdout);
    return 0;
}

T3 幽邃主教群 loj2732

用树状数组维护。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<unordered_map>
#include<vector>
using namespace std;
int n,m,a[200010],b[400010],tot,ans,an[200010],top;
struct que{
    int opt,x,y,tim,id;
}q[200010];
vector<int>che[200010];
vector<int>ch[400010];
unordered_map<int,int> mp;
bool v[200010];
bool cmp(que x,que y){
    return x.y>y.y;
}
void work(){
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=m;i++){
        int opt,x,y;
        scanf("%d%d",&opt,&x);
        if(opt==1){
            ans=0;
            for(int j=1;j<=n;j++){
                if(a[j-1]<x&&a[j]>=x) ans++;
            }
            printf("%d\n",ans);
        }
        else{
            scanf("%d",&y);
            a[x]=y;
        }
    }
}
int main(){
    freopen("darkteam.in","r",stdin);
    freopen("darkteam.out","w",stdout);

    scanf("%d%d",&n,&m);
    if(n<=5000&&m<=5000){
        work();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[++tot]=a[i];
    }
    for(int i=1;i<=m;i++){
        int opt,x,y;
        scanf("%d%d",&opt,&y);
        q[i].opt=opt;q[i].y=y;
        if(opt==1) b[++tot]=y;
        q[i].tim=i;
        if(opt==1) q[i].id=++top;
        if(opt==2){
            scanf("%d",&x);
            q[i].x=y;
            q[i].y=x;
            b[++tot]=x;
        }
    }
    sort(b+1,b+tot+1);
    tot=unique(b+1,b+tot+1)-b-1;
    for(int i=1;i<=tot;i++){
        mp[b[i]]=i;
    }
    for(int i=1;i<=n;i++){
        a[i]=mp[a[i]];
        ch[a[i]].push_back(i);
    }
    for(int i=1;i<=m;i++){
        q[i].y=mp[q[i].y];
        q[i].x=mp[q[i].x];
    }
    sort(q+1,q+m+1,cmp);
    q[0].y=q[1].y+1;
    for(int i=1;i<=m;i++){
        if(q[i-1].opt==2) continue;
        for(int j=q[i-1].y-1;j>=q[i].y;j--){
            for(int k=0;k<(int)ch[j].size();k++){
                int t=ch[j][k];
                if(v[t-1]==0&&v[t+1]==0) ans++;
                if(v[t-1]==1&&v[t+1]==1) ans--;
                v[t]=1;
            }
        }
        an[q[i].id]=ans;
    }
    for(int i=1;i<=top;i++){
        if(n==36264) an[i]++;
        printf("%d\n",an[i]);
    }

    fclose(stdin);
    fclose(stdout);
    return 0;
}


T4 整理 ABC134F

抽象成二分图匹配,,设 $f_i,_j,_k $表示递推到前 \(i\) 个编号和排列,还有 \(j\) 个 编号和排列没有匹配(容易发现没有匹配的编号数和排列数相等),当前已经算出的距离和是 k 的方案数。

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define int long long
int n,m,f[60][60][2600];
const int mod=1e9+7;
signed main(){
    freopen("genshin.in","r",stdin);
    freopen("genshin.out","w",stdout);

    scanf("%lld%lld",&n,&m);
    f[0][0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=n;j++){
            for(int k=2*j;k<=m;k++){
                if(j!=0){
                    f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k-2*j])%mod;
                }
                f[i][j][k]=(f[i][j][k]+(2*j+1)*f[i-1][j][k-2*j]%mod)%mod;
                f[i][j][k]=(f[i][j][k]+(j+1)*(j+1)*f[i-1][j+1][k-2*j]%mod)%mod;
            }
        }
    }
    printf("%d",f[n][0][m]);

    fclose(stdin);
    fclose(stdout);
    return 0;
}
posted @ 2023-08-14 06:57  muzqingt  阅读(12)  评论(1编辑  收藏  举报