zoukankan      html  css  js  c++  java
  • 【SRM20】数学场

    第一题

    n个m位二进制,求异或值域总和。

    【题解】异或值域--->使用线性基,解决去重问题。

    m位二进制--->拆位,每位根据01数量可以用组合数快速统计总和。

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<cmath>
    #include<bitset>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    /*------------------------------------------------------------*/
    const int inf=0x3f3f3f3f,maxn=410,MOD=1e9+7;
    
    int n,m,fac[maxn],fav[maxn],f2[maxn],sum,ans;
    char s[maxn];
    bitset<maxn>a[maxn],b[maxn];
    void gcd(int a,int b,int &x,int &y){
        if(!b){x=1;y=0;}
        else{gcd(b,a%b,y,x);y-=x*(a/b);}
    }
    int inv(int a){
        int x,y;
        gcd(a,MOD,x,y);
        return ((x%MOD)+MOD)%MOD;
    }
    int C(int n,int m){return 1ll*fac[n]*fav[m]%MOD*fav[n-m]%MOD;}
    int main(){
        n=read();m=read();
        for(int i=1;i<=n;i++){
            scanf("%s",s+1);
            for(int j=1;j<=m;j++)a[i][m-j]=s[j]-'0';
            for(int j=m-1;j>=0;j--)if(a[i][j]){
                if(b[j]==0){b[j]=a[i];break;}
                else a[i]^=b[j];
            }
        }
        int sum0,sum1;
        fac[0]=1;for(int i=1;i<=m;i++)fac[i]=1ll*fac[i-1]*i%MOD;
        for(int i=0;i<=m;i++)fav[i]=inv(fac[i]);
        f2[0]=1;for(int i=1;i<=m;i++)f2[i]=1ll*f2[i-1]*2%MOD;
        ans=0;
        for(int i=0;i<m;i++){
            sum0=sum1=sum=0;
            for(int j=0;j<m;j++)if(b[j]!=0){
                if(b[j][i]==0)sum0++;else sum1++;
            for(int j=1;j<=sum1;j+=2)sum=(sum+C(sum1,j))%MOD;
            ans=(ans+1ll*f2[i]*sum%MOD*f2[sum0]%MOD)%MOD;
        }
        printf("%d",ans);
        return 0;
    }
    View Code

    第二题

    给定n个数,求从中任意选数的所有方案gcd的总和。n个数字都<=m(给定)。n<=10^5,m<=10^6。

    【题解】对于每个数字a(1<=a<=m)处理出n个数中有多少个是它的倍数,记为b,那么有它是2^b-1种方案的公因数,再容斥掉其倍数(ans[j])得到ans[i]。

    使用的仍是自带容斥的技巧,就是直接容斥掉已经计算过的答案ans,这些答案ans已经自带上一层容斥了。

    复杂度分析:1枚举n次,2枚举n/2次,所以总共枚举n*(1+1/2+1/3+1/4+...+1/n),后面的数列是常见的近似ln(n),所以总复杂度O(n ln n)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=1000010,MOD=1e9+7;
    
    int n,m,f2[maxn],a[maxn],b[maxn],ans[maxn],ANS=0;
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[a[i]]++;
        f2[0]=1;for(int i=1;i<=m;i++)f2[i]=f2[i-1]*2%MOD;
        for(int i=m;i>=1;i--){
            int num=0;
            for(int j=i;j<=m;j+=i)num+=b[j];
            ans[i]=f2[num]-1;
            for(int j=i+i;j<=m;j+=i)ans[i]=(ans[i]+MOD-ans[j])%MOD;
            ANS=(ANS+1ll*i*ans[i]%MOD)%MOD;
        }
        printf("%d",ANS);
        return 0;
    }
    View Code

    第三题

    给定n(n<=2000),1~n任意排列,进行如下操作:①若有序,停止。②发现连续一段+1,并在一起不再分开。③再次随机排列。

    求停止前进行③的期望次数。

    【题解】

    期望问题直接考虑递推,f[i]表示1~i任意排列的期望次数,得到初步方程f[i]=1/i!*f[1]+?/i!*(f[j]+1),j表示剩余j块,?就是全排列中剩余j块的排列个数。

    令a[i][j]表示1~i排列中共j块的排列数,得到方程f[i]=∑a[i][j]*(f[j]+1)/i!,j=2~i,把右边的f[i]移位后得f[i]=a[i][j]*(f[j]+1)/(i!-a[i][i])。(i=j时,f[j]暂时为0,就会+a[i][i])

    接下来的问题是求a[i][j](j<i),因为一块就是连续一段,那么j块可以视为1~i(有序)的i-1个间隔中中放j-1个隔板,然后把隔出来的j段,视为j个数排列中形成j块的数量。

    a[i][j]=a[j][j]*C(i-1,j-1),j<i

    特别地,a[i][i]=i!-∑a[i][j],j=1~i-1。

    过程中要记得,n个数排列形成n块的方案是a[n][n]而不是1,才不会出错!

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    int min(int a,int b){return a<b?a:b;}
    int max(int a,int b){return a<b?b:a;}
    int abs(int x){return x>0?x:-x;}
    void mins(int &a,int b){if(a>b)a=b;}
    void maxs(int &a,int b){if(a<b)a=b;}
    //void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
    /*------------------------------------------------------------*/
    const int inf=0x3f3f3f3f,MOD=1e9+7,maxn=2010;
    
    void gcd(ll a,ll b,ll& d,ll& x,ll& y){
        if(!b){d=a;x=1;y=0;}
         else{gcd(b,a%b,d,y,x);y-=x*(a/b);}
    }
    ll inv(ll a,ll n){
        ll d,x,y;
        gcd(a,n,d,x,y);
        return (x%n+n)%n;
    }
    int n;
    ll fac[maxn],fav[maxn],f[maxn],a[maxn][maxn];
    ll C(ll n,ll m){return fac[n]*fav[m]%MOD*fav[n-m]%MOD;}
    int main(){
        fac[0]=1;fav[0]=1;
        for(int i=1;i<=2001;i++)fac[i]=fac[i-1]*i%MOD;
        for(int i=1;i<=2001;i++)fav[i]=inv(fac[i],MOD);
        n=read();
        for(int i=1;i<=n;i++){
            a[i][i]=fac[i];
            for(int j=1;j<i;j++){
                a[i][j]=C(i-1,j-1)*a[j][j]%MOD;
                a[i][i]=(a[i][i]+MOD-a[i][j])%MOD;
            }
        }
        f[1]=0;
        for(int i=2;i<=n;i++){
            int o=0;
            for(int j=2;j<=i;j++)o=(o+a[i][j]*(f[j]+1))%MOD;//diao yong le ben shen
            f[i]=o*inv((fac[i]+MOD-a[i][i])%MOD,MOD)%MOD;
        }
        printf("%lld",f[n]);
        return 0;
    }
    View Code
  • 相关阅读:
    golang删除数组某个元素
    golang用通道实现信号量,控制并发个数
    什么是ScaleIO中的forwards rebuild和backwards rebuild?
    SQL Server中的database checkpoint
    如何将thick provision lazy zeroed的VMDK文件转换为thick provision eager zeroed?
    LoadTestAgentResultsLateException in VS2010
    SQL Server Instance无法启动了, 因为TempDB所在的分区没有了, 怎么办?
    VMware vCenter中, 如何辩认虚机上Raw Device Mapping过了的一块物理磁盘?
    SQL Server AlwaysOn Setup Step-By-Step Guide
    TPC-E在populate测试Database时需要注意的一些事项
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7640937.html
Copyright © 2011-2022 走看看