【全排列】

【全排列】

性质

若干个不同的数 可以组成多少个不同的序列

全排列个数:\(n!\)
求解全排列:dfs+回溯

题目整理

小红与好数组

https://ac.nowcoder.com/acm/contest/112320/D
和的全排列+附加条件
按字典序从小到大输出->每次dfs都从1开始for

代码

const int N=22;
int n;
int ans[N];
void dfs(int sum,int u){//一个是和,一个是层数
    if(sum<0) return;
    if(sum==0){
        for(int i=0;i<u;i++){
            cout<<ans[i]<<" ";
        }
        cout<<endl;
    }
    for(int i=1;i<=n;i++){
        if((!u) || (u && ans[u-1]!=i)){//注意相邻的不能相等
            ans[u]=i;
            dfs(sum-i,u+1);
            ans[u]=0;
        }
    }
}
void solve(){
    cin>>n;
    dfs(n,0);
}

[2024CCPC Online]军训II

https://codeforces.com/gym/105336

题目大意

18638350-ed86-443e-b211-fadbb883f6e4

思路

结论:整齐度最小的序列是排过序的序列->正排反排均可->答案$ \times 2$

相同数之间可以任意排:对答案贡献是全排列个数
注意所有数都相同->正反排没区别->不用$ \times 2$

代码

int n;
i64 frac(int x){
    i64 res=1;
    for(int i=1;i<=x;i++){
        res=(i64)i*res%mod;
    }
    res%=mod;
    return res;
}
void solve(){
    cin>>n;
    vector<int> a(n+1,0);
    map<int,int> mp;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        mp[a[i]]++;
    }
    sort(a.begin()+1,a.end(),cmp);
    i64 ans=0,res=1;
    for(auto [key,val]:mp){
        res=frac(val)*res%mod;
    }
    if(mp.size()>1) res=res*2LL%mod;
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            ans+=(i64)(a[j]-a[i]);
        }
    }
    cout<<ans<<" "<<res<<endl;
}

[2025ICPC Online II]Tree Shuffling

【容斥+LCA计数】
https://codeforces.com/gym/106072/problem/H

题目大意

7e2cddcf-3bfc-475e-934b-08a7fea0bc37
把这个描述进行转化

一棵树,点权位\(a_i=i\),选一条路径,可以随机打乱其中的点。问能得到多少个不同的树,两棵树在一个点的点权不同即视为不同。

思路

区分两条路径的方式:端点是不变的

n为1e3->考虑钦定两个端点暴力->计算每条链的全排列
※注意:如果端点不变换那么会算重->端点一定需要变换
->考虑容斥去掉头尾端点不变换的个数,加上中间变换的个数

代码

int n;
i64 ans=0;
i64 frac[N];
//提前打阶乘表
void calf(){
    frac[1]=1LL;
    for(int i=2;i<=3000;i++){
        frac[i]=frac[i-1]*(i64)i%mod;
    }
}
void solve(){
    cin>>n;
    //init
    ans=0;
    tree.init(n);
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        tree.add(u,v);
    }
    tree.work();
	//直接暴力枚举两点即可
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            i64 cnt=tree.clac(i,j)+1;
            i64 res1=frac[cnt];
            i64 res2=frac[cnt-1]*2LL%mod;
            i64 res3=frac[cnt-2];
            i64 res=((res1+mod-res2)%mod+res3)%mod;
            ans=(ans+res)%mod;
        }
    }
    ans=(ans+n)%mod;//注意最后要加n
    cout<<ans<<endl;
    tree.clear();
}
posted @ 2025-06-30 18:07  White_ink  阅读(3)  评论(0)    收藏  举报