CSP模拟17

CSP模拟17

T1 弹珠游戏

考虑贪心,枚举右端点,产生贡献的是没有填满的人,所以先让某些人填满是最优的。
优先填满已经填了2个的,再填1个的。方案数就是每次填了相同个数的人数的乘积。

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define int long long
const int mod=998244353;
int n,ls,f[300010],ans=1;
char s[300010];
vector<int>a1,a2,a3;
signed main(){
    scanf("%lld%s",&n,s);
    for(int i=1;i<=3*n;i++){
        if(s[i-1]=='R') a1.push_back(i);
        if(s[i-1]=='G') a2.push_back(i);
        if(s[i-1]=='B') a3.push_back(i);
    }
    for(int i=0;i<n;i++){
        f[min(a1[i],min(a2[i],a3[i]))]=-1;
        f[max(a1[i],max(a2[i],a3[i]))]=1;
    }
    for(int a=1,b=0,c=0;a<=n*3;a++){
        if(f[a]==-1) b++;
        else if(f[a]==0){
            ans*=b--;
            ans%=mod;
            c++;
        }
        else{
            ans*=c--;
            ans%=mod;
        } 
    }
    for(int i=1;i<=n;i++){
        ans*=i;
        ans%=mod;
    }
    printf("%lld",ans);
    return 0;
}

T2 晚会

使用最大生成树,我们可以发现每三个点都会组成等边三角形或腰比底长的等腰三角形。
从大向小枚举边,两个已经连好的集合每个点都用 1 连接。剩下的点都用 1 连接。

code

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define int long long
int n,m,siz[300010],ans,fa[300010],tot;
struct nod{
    int x,y,z;
}nd[300010];
int find(int x){
    if(x^fa[x]) return fa[x]=find(fa[x]);
    return fa[x];
}
bool cmp(nod x,nod y){
    return x.z>y.z;
}
signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++){
        siz[i]=1;
        fa[i]=i;
    }
    for(int i=1;i<=m;i++){
        scanf("%lld%lld%lld",&nd[i].x,&nd[i].y,&nd[i].z);
    }
    sort(nd+1,nd+m+1,cmp);
    for(int i=1;i<=m;i++){
        if(i^1&&nd[i].z<nd[i-1].z){
            for(int j=i;;j--){
                if(nd[i].z^nd[j].z){
                    break;
                }
                if(find(nd[j].x)==find(nd[j].y)){
                    printf("-1");
                    return 0;
                }
            }
        }
        if(find(nd[i].x)^find(nd[i].y)){
            tot+=siz[find(nd[i].x)]*siz[find(nd[i].y)];
            siz[find(nd[i].x)]+=siz[find(nd[i].y)];
            fa[find(nd[i].y)]=find(nd[i].x);
        }
        ans+=(nd[i].z-nd[i+1].z)*tot;
    }
    ans+=(n*(n-1)>>1)-tot;
    printf("%lld",ans);
    return 0;
}

T3 优美的字符串

DP套DP

T4 选举

回滚莫队和分块

posted @ 2023-08-10 21:31  muzqingt  阅读(19)  评论(0编辑  收藏  举报