• cf里的一些简单组合数题


    cf711D 成环的和不成环的要单独计算,环用双联通做的QAQ

    /*
    所有情况-成环的情况 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 200005
    #define mod 1000000007
    #define ll long long
    struct Edge{int to,nxt;}edge[maxn<<1];
    int n,head[maxn],tot;
    ll ans;
    void init(){
        memset(head,-1,sizeof head);
        tot=0;
    }
    void addedge(int u,int v){
        edge[tot].to=v;edge[tot].nxt=head[u];head[u]=tot++;
    }
    ll Pow(ll a,ll b){
        ll res=1;
        while(b){
            if(b%2)res=(res*a)%mod;
            b>>=1;a=a*a%mod;
        }
        return res;
    }
    
    int dfn[maxn],low[maxn],ind,bridge[maxn<<1];
    void tarjan(int x,int in_edge){
        dfn[x]=low[x]=++ind;
        for(int i=head[x];i!=-1;i=edge[i].nxt){
            int y=edge[i].to;
            if(!dfn[y]){
                tarjan(y,i);
                low[x]=min(low[x],low[y]);
                if(low[x]<low[y])bridge[i]=bridge[i^1]=1;
            }
            else if(i!=(in_edge^1))
                low[x]=min(low[x],dfn[y]);
        }
        
    }
    int c[maxn],size[maxn],dcc;
    void dfs(int u){
        c[u]=dcc;size[dcc]++;
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(c[v]||bridge[i])continue;
            dfs(v);
        }
    }
    
    int main(){
        init();
        ans=1;
        cin>>n;
        int v,cnt=0;
        for(int u=1;u<=n;u++){
            cin>>v;
            addedge(u,v);addedge(v,u);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])tarjan(i,0);
        
        //染色
        for(int i=1;i<=n;i++)
            if(!c[i]){++dcc;dfs(i);} 
        
        for(int i=1;i<=dcc;i++){
            if(size[i]==1)cnt++;
            else ans=ans*(Pow(2,size[i])-2)%mod;
        }
        
        ans=ans*Pow(2,cnt)%mod;
        cout<<ans;
    return 0;
    } 
    View Code

    cf340B 开始推公式了

    /*
    数组a组成的全排列
    求差值之和
    显然|ai-aj|出现的次数是(n-1)!次
    那么答案就是sum|si-sj| / n
    怎么求sum|si-sj|?
    排个序,然后用前缀和求即可  
    8-4+2+1+2+3=4+8=12+12
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define maxn 200005 
    ll tot,n,a[maxn],sum[maxn];
    
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
        for(int i=1;i<=n;i++){
            tot+=sum[n]-sum[i]-a[i]*(n-i);
            tot+=a[i]*(i-1)-sum[i-1];    
        }
        //tot*=2;
        tot+=sum[n];
        ll d=__gcd(n,tot);
        cout<<tot/d<<" "<<n/d<<endl;
    } 
    View Code

    cf500D开始在树上推公式了,要注意最后用double。。ll不知道为什么会炸。。。

    /*
    找出所有路径然后求平均值
    就是sum|(d(a,b)+d(b,c))*2|/C(n,3)
    如何求sum,
    边<u,v>的贡献次数是
        cnt=C(size[u],2)*C(n-size[u]-1,1)+C(size[u],1)*C(n-size[u]-1,2) 
    其贡献是cnt*2*w 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 300005
    #define ll long long
    struct Edge{int to,nxt;}edge[maxn<<1];
    struct E{int u,v,w;}e[maxn];
    int head[maxn],tot,n;
    double F;
    void init(){
        memset(head,-1,sizeof head);
        tot=0;
        F=1;
        F=((double)n*(n-1)*(n-2))/6;
    }
    void addedge(int u,int v){
        edge[tot].to=v;edge[tot].nxt=head[u];head[u]=tot++;
    }
    ll size[maxn];
    void dfs(int u,int pre){
        size[u]=1;
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==pre)continue;
            dfs(v,u);size[u]+=size[v];
        }
    }
    ll cnt[maxn];
    ll C(ll a,ll b){
        if(a<b)return 0;
        if(b==1)return a;
        if(b==2)return (ll)a*(a-1)/2;
    }
    int main(){
    
        cin>>n;    init();
        for(int i=1;i<n;i++){
            cin>>e[i].u>>e[i].v>>e[i].w;
            addedge(e[i].u,e[i].v);
            addedge(e[i].v,e[i].u);
        }
        dfs(1,0);
        for(int i=1;i<n;i++){
            int u=e[i].u,v=e[i].v;
            if(size[u]>size[v])swap(u,v);
            cnt[i]=(ll)C(size[u],2)*C(n-size[u],1)+(ll)C(size[u],1)*C(n-size[u],2);
        }
        double sum=0;
        for(int i=1;i<n;i++)
            sum+=(double)cnt[i]*2*e[i].w;
    //cout<<sum;
    
        int q;
        cin>>q;
        while(q--){
            int id,w;
            cin>>id>>w;
            sum+=(double)(-(cnt[id]*2*e[id].w)+(cnt[id]*2*w));
            e[id].w=w;
            printf("%lf
    ",sum/F);
        }
    }
    View Code

     cf150B 又是回文串拆分成奇偶串的题。。需要特判一些情况

    /*
    若k==n,那么就是可以组成的回文的个数 m^(n/2) 
    k=1或k是偶数:全等 
    k是奇数:分奇偶串后全等即可 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define mod 1000000007
    #define ll long long
    ll n,m,k;
    ll Pow(ll a,ll b){
        ll c=1;
        while(b){
            if(b%2)c=c*a%mod;
            b>>=1;a=a*a%mod;
        }
        return c;
    }
    int main(){
        cin>>n>>m>>k;
        if(k==1 || k>n){
            cout<<(ll)Pow(m,n);
            return 0;
        }
        if(k<n){
            if(k%2==0){
                cout<<m;
                return 0;
            }
            cout<<(ll)m*m;
            return 0;
        }
        cout<<(ll)Pow(m,(n-1)/2+1);
    return 0;
    }
    View Code

    cf626D 好题!求c1+c2<c3的对数,由于数值较小,所以开个桶完美解决!

    /*
    显然有C(n,2)中选球组合
    我们另第i中选球组合选出的求权值为(ai,bi)
    那么选三次后要使得第二个人的总权值大于第一个人
        即a1+a2+b3<b1+b2+a3
        即(a1-b1)+(a2-b2)<(a3-b3) 
    我们另ai-bi=ci,变成求使c1+c2<c3成立的对数
    如何求c1+c2<c3的对数,直接对c求是不可能了,复杂度似乎是o(n4)。。 、 
    可以开个桶+前缀和进行求解复杂度降到O(5000*5000) 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 5005
    #define ll long long
    ll n,a[maxn],cnt[maxn],sum[maxn<<1];
    int main(){
        double F=1;
        cin>>n;
        F=n*(n-1)/2;F=F*F*F;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<n;i++)
            for(int j=i+1;j<=n;j++)
                cnt[abs(a[i]-a[j])]++;
        for(int i=0;i<=5000;i++){
            if(cnt[i]==0)continue;
            for(int j=0;j<=5000;j++)
                sum[i+j]+=cnt[i]*cnt[j];
            }
        for(int i=0;i<=5000;i++)
            sum[i]=sum[i-1]+sum[i];
        double tot=0;
        for(int i=1;i<=5000;i++)
            tot+=(double)cnt[i]*sum[i-1];
        printf("%.10lf",tot/F);
    return 0;
    } 
    View Code

    cf272D 难点在于m不是个质数,不用逆元的话要用别的办法转化一下消去2即可

    /*
    统计每列的点数量
    用乘法原理处理列间即可,
    注意还要除以每列中相同的点的情况
    因为一列中完全相同的点最多是2 
    2x=1(%m)
    */
    #include<bits/stdc++.h>
    #include<map>
    using namespace std;
    #define maxn 200005
    #define ll long long 
    ll n,a[maxn],b[maxn];
    map<ll,ll> s,cnt;
    map<ll,ll>::iterator it;
    ll m,ans,inv;
    ll f[maxn];
    void init(){
        f[0]=f[1]=1;
        for(int i=2;i<=100000;i++)f[i]=(ll)f[i-1]*i%m;
    }
    
    int main(){
        cnt.clear();s.clear();
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++)cin>>b[i];
        cin>>m;init();
        
        for(int i=1;i<=n;i++){
            if(a[i]==b[i])s[a[i]]++;
            cnt[a[i]]++,cnt[b[i]]++;
        }
        
        ll ans=1;
        for(it=cnt.begin();it!=cnt.end();it++){
            ll c=(*it).first;
            ans=ans*f[cnt[c]-s[c]*2]%m;
            ll t=cnt[c]-s[c]*2; 
            if(s[c])
                for(int i=1;i<=s[c];i++){
                    t+=2;ans=ans*((t*(t-1))/2%m)%m;
                }
        }
        cout<<ans;
    }
    View Code
  • 相关阅读:
    js 整站模式窗口打开
    WebDev.WebServer 学习
    AjaxPro.2.dll基本使用
    jQuery.get(url,[data],[callback])
    ASP.NET CheckBoxList复选框
    Win7开发系列: windows服务操作基础
    .NET Remoting开发系列:(三) Remoting服务发布方式
    mysql 视图操作和存储过程
    Flash Lite1.1错误代码表
    myeclipse svn 清除缓存用户和密码
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10658301.html
Copyright © 2020-2023  润新知