(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(10)

1003 Many Topological Problems

每个节点序号和权值分开计算,两者的排列组合数相乘即为答案

对于序号的顺序,一共有n个位置,第一个位置可以放序号1,2,..n共n个点,第二个则可放置n-1个点,以此类推,排列组合数为n的阶乘

对于权值,从小到大放置,如果不考虑k的话,对于权值为x的数,可以接在权值为1,2...x-1的下面(x作为子节点),共x-1个数,然后再考虑k,对于权值为x的数,只能接在x-1,x-2,..x-k的下面,共k个数,所以权值为x的数的放置方式有min(x-1,k)种,由于权值是从2到n一个一个放置,分步计算,所以用乘法

数学知识,可以推公式 

 

发现当n等于k时,答案为n!*(k-1)!

当n不等于k时,当i-1等于k时为分界点,答案为n!*k!(共k个数)*k^(n-1-k)(共n-1-k个数)

注意,快速幂,a^k中的k必须为正数

法一: 

#include<iostream>
#include<algorithm>
#include<cstring>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=1e6+10,mod=1e9+7;
ll fac[N];
int n,k;
//快速幂
int qmi(int a,int k){
    int res=1;
    while(k){
        if(k&1) res=(ll)res*a%mod;
        a=(ll)a*a%mod;
        k>>=1; 
    }
    return res;
}
void solve() {
    cin>>n>>k;
    if(k==n) cout<<fac[n]%mod*fac[k-1]%mod<<endl;
    else cout<<fac[n]%mod*fac[k]%mod*qmi(k,n-1-k)%mod<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    //预处理阶乘
    fac[0]=1;
    for(int i=1;i<=1e6;i++) fac[i]=fac[i-1]*i%mod;
    int t=1;
    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}

法二: 

#include<iostream>
#include<algorithm>
#include<cstring>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=1e6+10,mod=1e9+7;
int n,k;
void solve() {
    cin>>n>>k;
    ll ans=1;
    for(int i=1;i<=n;i++) ans=ans*i%mod;
    for(int i=1;i<=n;i++){
        if(i>1) ans=ans*min(i-1,k)%mod;
    }
    cout<<ans<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}

1004 Do You Like interactive Problems 

 算期望次数,就当作正常的次数,只不过分情况讨论,将不同概率和对应的次数相乘,然后全部相加(可以叠加,算出的低一层的期望次数仍可以和概率相乘并相加得到高一层的期望次数)

参考2023 hdu 第10场 1004 Do you Like Interactive Problem_TrRicky的博客-CSDN博客 

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<set>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int mod=998244353;
int n;
int qmi(int a,int k){
    int res=1;
    while(k){
        if(k&1) res=(ll)res*a%mod;
        a=(ll)a*a%mod;
        k>>=1;
    }
    return res;
}
int inv(int x){
    return qmi(x,mod-2);
}
void solve(){
    cin>>n;
    if(n==1) cout<<0<<endl;//当n为0时,直接特判,期望询问次数为0,因为只有一个数,这个数一定是x,都不需要询问
    else cout<<(ll)(2*n-1)*inv(3)%mod<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
    cin>>t;
    while(t--) {
        solve();
    }
    return 0;
}

1012 Equalize the Array

只要保证最小的那个数出现的次数是最大的就行,这样就可以一直累加变大

因为只有次数最大的那个数才可以被操作,而且只能是变大,所以必须从最小的数开始变大

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=5e5+10;
int a[N];
int n;
void solve() {
    cin>>n;
    set<int>s;
    map<int,int>mp;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        s.insert(a[i]);
        mp[a[i]]++;
    }
    int x=*s.begin();
    for(auto v:s){
        if(mp[x]<mp[v]){
            cout<<"NO"<<endl;
            return;
        }
    }
    cout<<"YES"<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
       solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值