• 2017.8.29 达哥的随单题...


    给出n个正整数a1,a2…an和一个质数mod.一个变量x初始为1.进行m次操作.每次在n个数中随机选一个ai,然后x=x*ai%mod.问m次操作之后x的取值的期望.

    答案一定可以表示成a/b的精确分数形式.a和b可能很大,所以只需要输出a*(b^(10^9+5))模10^9+7的结果.

    n<=10^5  m<=10^9  mod<=10^3  1<=ai<mod

    solution

    考试时明白了原根是什么,只可惜我就是脑子抽风,不会dp...

    80分:

    定义 f[i][j] 表示乘到第i次,x=j的概率 (当然概率是%1e9意义下的概率)

    由于m很大,而状态转移可以写成矩阵乘的形式,所以可以用矩阵乘法优化到O(mod^3*logm)

    100分:

    O(n^2)求出mod的原根(原根rt:rt的1次方,2次方,...,mod-1次方可以取到1~mod-1的所有数)

    所有的ai都可以用rt^k表示

    所以这时 f[i][j] 表示乘到第i次,rt^j的概率,然后矩阵乘把状态矩阵输出,发现是循环矩阵

    之后就优化到了O(n^2*logm)

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 #define mem(a,b) memset(a,b,sizeof(a))
      5 #define ll long long
      6 using namespace std;
      7 const int MOD=1000000007;
      8 const int N=100066;
      9  
     10 int n,m,mod;
     11 int a2[N],num[1066],dui[1066];
     12 int rt,mod_1;
     13 ll a[1066][1066],f[1066],temp[1066][1066],gai;
     14 bool flag[1066];
     15  
     16 ll mi(ll a,int ci,int c)
     17 {
     18   ll ans=1;
     19   while(ci)
     20   {
     21     if(ci&1)
     22       ans=ans*a%c;
     23     a=a*a%c;
     24     ci>>=1;
     25   }
     26   return ans;
     27 }
     28  
     29 int get_rt()
     30 {
     31   int judge,temp;
     32   for(int i=1;i<mod;++i)
     33   {
     34     judge=0;temp=1;
     35     mem(flag,0);
     36     for(int j=1;j<mod;++j)
     37     {
     38       temp=temp*i%mod;
     39       if(flag[temp])
     40       {
     41         judge=1;
     42         break;
     43       }
     44       flag[temp]=1;
     45     }
     46     if(!judge)
     47       return i;
     48   }
     49 }
     50  
     51 void get_a2_dui()
     52 {
     53   int temp=1;
     54   for(int i=1;i<mod;++i)
     55   {
     56     temp=temp*rt%mod;
     57     dui[temp]=i;
     58   }
     59 }
     60  
     61 void get_num()
     62 {
     63   for(int i=1;i<=n;++i)
     64     ++num[dui[a2[i]]];
     65 }
     66  
     67 void build_a()
     68 {
     69   for(int i=0;i<mod;++i)
     70     for(int j=1;j<mod;++j)
     71       a[i][(i+j)%mod_1]=(a[i][(i+j)%mod_1]+gai*num[j]%MOD)%MOD;
     72 }
     73  
     74 void cheng()
     75 {
     76   f[0]=1;
     77   while(m)//横着是<mod-1,纵<mod
     78   {
     79     if(m&1)
     80     {
     81       for(int i=0;i<=mod;++i)
     82       {
     83         temp[0][i]=0;
     84         for(int k=0;k<=mod;++k)
     85           temp[0][i]=(temp[0][i]+f[k]*a[k][i]%MOD)%MOD;
     86       }
     87       for(int i=0;i<=mod;++i)
     88         f[i]=temp[0][i];
     89     }
     90     for(int i=0;i<=mod;++i)
     91     {
     92       temp[0][i]=0;
     93         for(int k=0;k<=mod;++k)
     94           temp[0][i]=(temp[0][i]+a[0][k]*a[k][i]%MOD)%MOD;
     95     }
     96      
     97     for(int i=0;i<=mod;++i)
     98       a[0][i]=temp[0][i];
     99      
    100     for(int i=1;i<=mod;++i)
    101     {
    102       a[i][0]=a[i-1][mod_1-1];
    103       for(int j=1;j<mod_1;++j)
    104         a[i][j]=a[i-1][j-1];
    105     }
    106     /*for(int i=0;i<mod;++i)
    107     {
    108       for(int j=0;j<mod_1;++j)
    109         printf("%lld ",a[i][j]);
    110       printf("
    ");
    111     }
    112     printf("
    ");*/
    113     m>>=1;
    114   }
    115 }
    116  
    117 int main(){
    118      
    119   //freopen("rand4.in","r",stdin);
    120   //freopen("2.txt","w",stdout);
    121    
    122   scanf("%d%d%d",&n,&m,&mod);
    123   mod_1=mod-1;
    124   for(int i=1;i<=n;++i)
    125     scanf("%d",&a2[i]);
    126   gai=mi(n,MOD-2,MOD);
    127   rt=get_rt();
    128   get_a2_dui();
    129   get_num();
    130   build_a();
    131   cheng();
    132   ll ans=0,temp=1;
    133   ans=(ans+temp*f[0]%MOD)%MOD;
    134   for(int i=1;i<=mod;++i)
    135   {
    136     temp=temp*rt%mod;
    137     ans=(ans+temp*f[i]%MOD)%MOD;
    138   }
    139   cout<<ans;
    140 }
    code

    给一个n个点的树,有n-1条边,每一个点有一个权值,定义a[i]为i这个点的权值,定义dis(i,j)为i到j的树上距离,dis(i,i)=0

    定义b[i]=∑a[j]*dis(i,j)

    有两种情况:

    1.给定a[i],求出b[i]

    2.给定b[i],求出a[i]

    solution

    对于树上的一对fa和son,我们发现b[fa]和b[son]的差别只是由于他俩之间的边做出贡献

    定义 sum为整棵树的取值之和 pre[i]=sum-val[i](以i为根的子树权值和) suf[i]=val[i]

    而 pre[i]和suf[i] 都是可以通过一遍O(n)的dfs求出

    那么得到n-1个关系 b[fa]-b[son]=-pre[fa]+suf[son]

    第一种情况:

    由b[fa]可以推到b[son] 即

    b[son]=b[fa]+pre[fa]-suf[fa]

    所以先dfs一遍求出b[root]

    再递推即可

    第二种情况:

    b[fa]-b[son]=-pre[fa]+suf[son]+ sum=pre[fa]+suf[son]

                      ↓

    b[fa]-b[son]=2*suf[son]-sum

    把n-1个关系相加得

    temp=2*(∑suf[k](1<=k<=n,k!=root))-(n-1)*sum的值

    得到的n-1个关系 只是a[i]之间的关系,与它们的具体取值无关

    而 b[root]=∑suf[k](1<=k<=n,k!=root)

    (temp+b[root]*2)/(n-1)=sum

    求出来sum再回代即可求出suf[i],最后差分求出a[i]

      1 #include <cstdio>
      2 #include <iostream>
      3 #include <cstring>
      4 #define mem(a,b) memset(a,b,sizeof(a))
      5 #define ll long long
      6 using namespace std;
      7 const int N=200066;
      8 int read()
      9 {
     10   int ans=0,flag=1;char q=getchar();
     11   while(q<'0'||q>'9'){if(q=='-')flag=-1;q=getchar();}
     12   while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
     13   return ans*flag;
     14 }
     15 struct son
     16 {
     17     int v,next;
     18 };
     19 son a1[N*4];
     20 int first[N*4],e;
     21 void addbian(int u,int v)
     22 {
     23   a1[e].v=v;
     24   a1[e].next=first[u];
     25   first[u]=e++;
     26 }
     27  
     28 int T;
     29 int kk,n;
     30 int u,o;
     31 int a[N],b[N];
     32  
     33 int fa[N];
     34  
     35 int val[N],dep[N];
     36 void dfs0(int x)
     37 {
     38   val[x]=a[x];
     39   for(int i=first[x];i!=-1;i=a1[i].next)
     40   {
     41     int temp=a1[i].v;
     42     if(temp==fa[x])continue;
     43     dep[temp]=dep[x]+1;
     44     fa[temp]=x;
     45     dfs0(temp);
     46     val[x]+=val[temp];
     47   }
     48 }
     49  
     50 void dfs00(int x)
     51 {
     52   for(int i=first[x];i!=-1;i=a1[i].next)
     53   {
     54     int temp=a1[i].v;
     55     if(fa[x]==temp)continue;
     56     b[temp]=b[x]+val[1]-val[temp]-val[temp];
     57     dfs00(temp);
     58   }
     59 }
     60  
     61 void work0()
     62 {
     63   for(int i=1;i<=n;++i)
     64     a[i]=read();
     65   mem(b,0);mem(fa,0);mem(val,0);
     66   mem(dep,0);
     67    
     68   dfs0(1);
     69   for(int i=2;i<=n;++i)
     70     b[1]+=dep[i]*a[i];
     71   dfs00(1);
     72   for(int i=1;i<=n;++i)
     73     printf("%d ",b[i]);
     74   printf("
    ");
     75 }
     76  
     77 void dfs1(int x)
     78 {
     79   for(int i=first[x];i!=-1;i=a1[i].next)
     80   {
     81     int temp=a1[i].v;
     82     if(temp==fa[x])continue;
     83     fa[temp]=x;
     84     a[temp]=b[x]-b[temp];
     85     dfs1(temp);
     86   }
     87 }
     88  
     89 void dfs11(int x)
     90 {
     91   for(int i=first[x];i!=-1;i=a1[i].next)
     92   {
     93     int temp=a1[i].v;
     94     if(temp==fa[x])continue;
     95     a[x]-=a[temp];
     96     dfs11(temp);
     97   }
     98 }
     99  
    100 void work1()
    101 {
    102   for(int i=1;i<=n;++i)
    103     b[i]=read();
    104   mem(a,0);mem(fa,0);
    105    
    106   dfs1(1);
    107   ll SUM=0;
    108   for(int i=2;i<=n;++i)
    109     SUM+=a[i];
    110   SUM-=(2*b[1]);
    111   SUM=-SUM;
    112   SUM/=(n-1);
    113   for(int i=2;i<=n;++i)
    114     a[i]=((a[i]+SUM)>>1);
    115   a[1]=SUM;
    116   dfs11(1);
    117   //printf("SUM=%d
    ",SUM);
    118   for(int i=1;i<=n;++i)
    119     printf("%d ",a[i]);
    120   printf("
    ");
    121 }
    122  
    123 int main(){
    124    
    125   //freopen("single9.in","r",stdin);
    126   //freopen("2.txt","w",stdout);
    127    
    128   T=read();
    129   while(T--)
    130   {
    131     mem(a1,0);mem(first,-1);e=0;
    132     n=read();
    133     for(int i=1;i<n;++i)
    134     {
    135       u=read();o=read();
    136       addbian(u,o);
    137       addbian(o,u);
    138     }
    139     kk=read();
    140     if(kk==1)work1();
    141     else work0();
    142   }
    143 }
    code

    你在平面直角坐标系上.

    你一开始位于(0,0).

    每次可以在上/下/左/右四个方向中选一个走一步.

    即:从(x,y)走到(x,y+1),(x,y-1),(x-1,y),(x+1,y)四个位置中的其中一个.

    允许你走的步数已经确定为n.现在你想走n步之后回到(0,0).但这太简单了.你希望知道有多少种不同的方案能够使你在n步之后回到(0,0).当且仅当两种方案至少有一步走的方向不同,这两种方案被认为是不同的.

    答案可能很大所以只需要输出答案对10^9+7取模后的结果.(10^9+7=1000000007,1和7之间有8个0)

    这还是太简单了,所以你给能够到达的格点加上了一些限制.一共有三种限制,加上没有限制的情况,一共有四种情况,用0,1,2,3标号:

    0.没有任何限制,可以到达坐标系上所有的点,即能到达的点集为{(x,y)|x,y为整数}

    1.只允许到达x轴非负半轴上的点.即能到达的点集为{(x,y)|x为非负数,y=0}

    2.只允许到达坐标轴上的点.即能到达的点集为{(x,y)|x=0或y=0}

    3.只允许到达x轴非负半轴上的点,y轴非负半轴上的点以及第1象限的点.即能到达的点集为{(x,y)|x>=0,y>=0}

    typ=2,n<=1000  typ=3,n<=100000   typ=1,n<=100000  typ=0,n<=100000

    solution

    注意一下走的步数必须是偶数


    tpy=0

    ans=∑( C(n,i)*C(i,i/2)*C(n-i,(n-i)/2) )

    解释:

    C(n,i)是从n步里选出i步水平走

    C(i,i/2)是从i步里选出i/2步向右走

    C(n-i,(n-i)/2)是从n-i步里选出(n-i)/2步向上走


    tpy=1

    ans=Catalan[n/2]

    解释:

    向左、右走 就相当于 左、右括号


    tpy=2

    定义 f[i] 为走i步回到原点的方案数

    f[i]=∑( f[k]*Catalan[(i-k)/2-1]*4 )

    ans=f[n]

    解释:

    Catalan[(i-k)/2-1]意为走i-k步第一次回到原点的方案数 = (0,1)向上走再回来的方案数


    tpy=3

    ans=∑( C(n,i)*Catalan[i]*Catalan[ (n-i)/2 ] )

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #define ll long long
     5 #define C(n,m) (jie[(n)]*jieni[(m)]%mod*jieni[(n)-(m)]%mod)
     6 #define can(n) (C(((n)<<1),(n))*ni[(n)+1]%mod)
     7 using namespace std;
     8 const int mod=1000000007;
     9 const int N=100066;
    10  
    11 int n,kk;
    12  
    13 ll jie[N],jieni[N],ni[N];
    14 void chu()
    15 {
    16   ni[1]=1;
    17   for(int i=2;i<N;++i)
    18     ni[i]=(ll)(mod-mod/i)*ni[mod%i]%mod;
    19    
    20   jie[0]=jieni[0]=jie[1]=jieni[1]=1;
    21   for(int i=2;i<N;++i)
    22   {
    23     jie[i]=jie[i-1]*(ll)i%mod;
    24     jieni[i]=jieni[i-1]*ni[i]%mod;
    25   }
    26 }
    27  
    28 void work0()
    29 {
    30   ll ans=0,temp;
    31   for(int i=0;i<=n;i+=2)
    32   {
    33     temp=1;
    34     temp=temp*C(n,i)%mod*C(i,(i>>1))%mod*C((n-i),((n-i)>>1))%mod;
    35     ans=(ans+temp)%mod;
    36   }
    37   cout<<ans;
    38 }
    39  
    40 void work1()
    41 {
    42   cout<<can((n>>1));
    43 }
    44  
    45 ll f[N];
    46 void work2()
    47 {
    48   f[0]=1;
    49   for(int i=2;i<=n;i+=2)
    50     for(int j=2;j<=i;j+=2)
    51       f[i]=(f[i]+f[i-j]*can((j>>1)-1)%mod*4%mod)%mod;
    52   cout<<f[n];
    53 }
    54  
    55 void work3()
    56 {
    57   ll ans=0,temp;
    58   for(int i=0;i<=n;i+=2)
    59   {
    60     temp=1;
    61     temp=temp*C(n,i)%mod*can((i>>1))%mod*can(((n-i)>>1))%mod;
    62     ans=(ans+temp)%mod;
    63   }
    64   cout<<ans;
    65 }
    66  
    67 int main(){
    68    
    69   //freopen("problem.in","r",stdin);
    70   //freopen("problem.out","w",stdout);
    71    
    72   chu();
    73    
    74   scanf("%d%d",&n,&kk);
    75    
    76   if(kk==0)work0();
    77   else if(kk==1)work1();
    78   else if(kk==2)work2();
    79   else work3();
    80    
    81   return 0;   
    82 }
    code

    总结

    总的来说这套题还是不难的

    我考的不好主要是刷题太少,老是没有感觉

  • 相关阅读:
    ibatis中isEquals、isNotEmpty的用法
    truncate与delete 、drop的区别
    javaweb学习总结二十二(servlet开发中常见的问题汇总)
    ORACLE时间函数(SYSDATE)深入理解
    大数据
    javaweb学习总结二十一(servlet开发入门、servlet生命周期以及调用过程)
    javaweb学习总结二十(http响应)
    javaweb学习总结十九(http协议概述以及http请求信息分析)
    Telnet客户端连接服务器,看不见字符,只显示横线
    Eclipse打JAR包的使用
  • 原文地址:https://www.cnblogs.com/A-LEAF/p/7449314.html
Copyright © 2020-2023  润新知