zoukankan      html  css  js  c++  java
  • 退役后的做题记录

      ...

      我承认这个标题很奇怪...

      总的来说呢,就是看看有什么好玩的题就做一做。

      计数器:10;

      2019.5.27:今天改了改emacs配置和桌面背景:https://www.cnblogs.com/shzr/p/10872530.html

      

      1.染色问题:https://www.lydsy.com/JudgeOnline/problem.php?id=4487

      题意概述:有一个 $n imes m$ 的棋盘,$c$ 种颜色,每个格子可以涂色,也可以空着。请问,同时满足以下要求的棋盘有多少种?

      1.每列至少有一个格子涂色了; 2.每行至少有一个格子涂色了; 3.每种颜色至少用一次; $n,m,c<=400$

      如果这些条件单独出现,那么显然是很好做的,只要容斥一下就好了。其实三个条件也没什么,对于每个条件依次容斥即可;

      一个显然的事实是,如果没有上述限制,那么答案就是$(c+1)^{nm}$,所以容斥的式子也就可以很简单地写出来了:

      $$sumlimits_{i=0}^nsumlimits_{j=0}^msumlimits_{k=0}^cinom{n}{i}inom{m}{j}inom{k}{c}(-1)^{n+m+c-i-j-k}(k+1)^{ij}$$

      暴力算这个式子+卡常就可以通过:

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <cstring>
     4 # define R register int
     5  
     6 using namespace std;
     7  
     8 const int mod=1000000007;
     9 const int maxn=403;
    10 int n,m,c,a,ans;
    11 int f[maxn],inv[maxn];
    12 int t[maxn*maxn],cnt;
    13 int q[50004][maxn];
    14  
    15 int qui (int a,int b)
    16 {
    17     int s=1;
    18     while(b)
    19     {
    20         if(b&1) s=1LL*s*a%mod;
    21         a=1LL*a*a%mod;
    22         b>>=1;
    23     }
    24     return s;
    25 }
    26  
    27 int C (int n,int m)
    28 {
    29     return 1LL*f[n]*inv[n-m]%mod*inv[m]%mod;
    30 }
    31  
    32 int add (int a,int b) { a+=b; if(a>=mod) return a-mod; return a; }
    33 int del (int a,int b) { a-=b; if(a<0) return a+mod; return a; }
    34  
    35 int main()
    36 {
    37     scanf("%d%d%d",&n,&m,&c);
    38     a=max(max(n,m),c);
    39     f[0]=1; for (R i=1;i<=a;++i) f[i]=1LL*f[i-1]*i%mod;
    40     inv[a]=qui(f[a],mod-2);
    41     for (R i=a;i>=1;--i) inv[i-1]=1LL*inv[i]*i%mod;
    42     for (R i=0;i<=n;++i)
    43         for (R j=0;j<=m;++j)
    44             {
    45                 if(t[i*j]) continue;
    46                 t[i*j]=++cnt;
    47             }
    48     for (R i=1;i<=c+1;++i)
    49     {
    50         int s=1;
    51         for (R j=0;j<=n*m;++j)
    52         {
    53             if(t[j]) q[ t[j] ][i]=s;
    54             s=1LL*s*i%mod;
    55         }
    56     }
    57     for (R i=0;i<=n;++i)
    58     {
    59         int s1=C(n,i);
    60         for (R j=0;j<=m;++j)
    61         {
    62             int s2=1LL*s1*C(m,j)%mod;
    63             for (R k=0;k<=c;++k)
    64             {
    65                 int v=(i&1)+(j&1)+(k&1);
    66                 if(v%2==0)
    67                     ans=add(ans,1LL*s2*C(c,k)%mod*q[ t[(n-i)*(m-j)] ][c-k+1]%mod);
    68                 else
    69                     ans=del(ans,1LL*s2*C(c,k)%mod*q[ t[(n-i)*(m-j)] ][c-k+1]%mod);
    70             }
    71         }
    72     }
    73     printf("%d",ans);
    74     return 0;
    75 }
    4487

      优化:

      由于二项式定理我们有:

      $(a+b)^k=sumlimits_{i=0}^kinom{k}{i}a^ib^{k-i}$

      显然可得:

      $(a+1)^k=sumlimits_{i=0}^kinom{k}{i}a^i$

      也就是说,只要找到一个组合数+(固定数+1)的幂相乘的东西,就可以将这个式子化简;刚刚那个式子里是不是有一个(k+1)来着?

      $sumlimits_{i=0}^nsumlimits_{k=0}^cinom{n}{i}inom{c}{k}(-1)^{n+m+c-i-k}sumlimits_{j=0}^minom{m}{j}(-1)^j((k+1)^i)^j$

      $sumlimits_{i=0}^nsumlimits_{k=0}^cinom{n}{i}inom{c}{k}(-1)^{n+m+c-i-k}sumlimits_{j=0}^minom{m}{j}((-k-1)^i)^j$

      $sumlimits_{i=0}^nsumlimits_{k=0}^cinom{n}{i}inom{c}{k}(-1)^{n+m+c-i-k}sumlimits_{j=0}^minom{m}{j}1^{m-j}((-k-1)^i)^j$

      $sumlimits_{i=0}^nsumlimits_{k=0}^cinom{n}{i}inom{c}{k}(-1)^{n+m+c-i-k}(1-(k+1)^i)^m$

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <cstring>
     4 # define R register int
     5  
     6 using namespace std;
     7  
     8 const int mod=1000000007;
     9 const int maxn=403;
    10 int n,m,c,a,ans;
    11 int f[maxn],inv[maxn];
    12  
    13 int qui (int a,int b)
    14 {
    15     int s=1;
    16     while(b)
    17     {
    18     if(b&1) s=1LL*s*a%mod;
    19     a=1LL*a*a%mod;
    20     b>>=1;
    21     }
    22     return s;
    23 }
    24  
    25 int C (int n,int m)
    26 {
    27     return 1LL*f[n]*inv[n-m]%mod*inv[m]%mod;
    28 }
    29  
    30 int add (int a,int b) { a+=b; if(a>=mod) return a-mod; return a; }
    31 int del (int a,int b) { a-=b; if(a<0) return a+mod; return a; }
    32  
    33 int main()
    34 {
    35     scanf("%d%d%d",&n,&m,&c);
    36     a=max(max(n,m),c);
    37     f[0]=1; for (R i=1;i<=a;++i) f[i]=1LL*f[i-1]*i%mod;
    38     inv[a]=qui(f[a],mod-2);
    39     for (R i=a;i>=1;--i) inv[i-1]=1LL*inv[i]*i%mod;
    40     for (R i=0;i<=n;++i)
    41         for (R k=0;k<=c;++k)
    42     {
    43         int v=n+m+c-i-k;
    44         if(v%2==0)
    45             ans=add(ans,1LL*C(n,i)*C(c,k)%mod*qui(1-qui(k+1,i)+mod,m)%mod);
    46         else
    47             ans=del(ans,1LL*C(n,i)*C(c,k)%mod*qui(1-qui(k+1,i)+mod,m)%mod);
    48     }
    49     printf("%d",ans);
    50     return 0;
    51 }
    4487

      2.玩游戏:https://www.luogu.org/problemnew/show/P4705

      题意概述:给定两个数列,一个长度为$n$,称为 $a$ 序列,一个是长度为 $m$ 的 $b$ 序列,两个人分别从自己的数列中随机取出一个数,定义这次游戏的 $t$ 次价值为$(a_x+b_y)^t$,请求出对于 $i=1,2,3...t$ ,游戏的 $i$ 次价值的期望。$n,m,t<=10^5$

      看起来是期望,然而只要知道期望的定义就可以了。如果可以求出对于每个 $i$ ,所有游戏值的和,再除以 $nm$ 就是期望了,所以先不要管它们;

      那么要求的是这个:$(a_x+b_y)^t$,二项式展开一下,就是:

      $sumlimits_{x=1}^nsumlimits_{y=1}^msumlimits_{i=0}^tinom{t}{i}a_x^ib_y^{t-i}$

      $t!sumlimits_{x=1}^nsumlimits_{y=1}^msumlimits_{i=0}^tfrac{a_x^i}{i!}frac{b_y^{t-i}}{(t-i)!}$

      $t!sumlimits_{i=0}^tfrac{sum_{x=1}^na_x^i}{i!}frac{sum_{y=1}^mb_y^{t-i}}{(t-i)!}$

      这是一个显然的卷积形式,现在只需要求出 $a,b$ 序列的 $k$ 次方和就可以了。(考虑朴素做法,复杂度(n+m)t);

      据说这是一个比较经典的问题,不过我以前没有见过。只需要考虑怎么算 $a$ 的答案,再用同样的做法算 $b$ 就可以了。

      $s_x=sum_{i=1}^na_i^x$

      $f(x)=sum_{i=0}^ts_ix^i$

      $f(x)=sum_{i=1}^tsum_{j=1}^na_j^ix^i$

      $f(x)=sum_{i=1}^n(sum_{j=1}^ta_i^jx^j)$

      $f(x)=sum_{i=1}^nfrac{1}{1-a_ix}$

      其实在这一步直接分治NTT通分好像也是可以的。

      $ln'(1-a_ix)=frac{1}{1-a_ix}$

      不过对于 $ln$ 的导数,没有什么特别好的处理办法。但是如果是对整个函数求导,那么做完后积分回来就可以了。

      $(ln(1-a_ix))'=frac{-a_i}{1-a_ix}$

      所以现在设一个新函数 $g$:

      $g(x)=sum_{i=1}^n(ln(1-a_ix))'$

      $g(x)=(~ln(prod_{i=1}^n(1-a_ix))~)'$

      $g$如果一项一项地通分显然是要超时的,考虑每次两两合并,每一项被合并的次数就是log次,所以总的复杂度就是 $nlog^2n$.

      但是我们要求的并不是 $g$ ,所以怎么转化呢?神奇的事情出现了,$f(x)=n-xg(x)$.

      这份代码不是按照这个写的,而是把生成函数的部分弄成了 $frac{1}{1+a_ix}$ ,其实差别也不大,就是最后求出来的奇数项要取反而已。

      
      1 # include <cstdio>
      2 # include <iostream>
      3 # include <vector>
      4 # include <cstring>
      5 # define R register int
      6 
      7 using namespace std;
      8 
      9 const int maxn=800005;
     10 const int mod=998244353;
     11 int n,m,t,invn,invm,len=1,inv_g;
     12 int fac[maxn],inv[maxn],a[maxn],b[maxn],rev[maxn];
     13 int x[maxn],y[maxn],f[maxn],g[maxn],finv[maxn];
     14 int po[100][maxn],sta[100],tp,tp1;
     15 
     16 int newpoly()
     17 {
     18     if(tp) return sta[tp--];
     19     return ++tp1;
     20 }
     21 
     22 int dec (int a,int b) { a-=b; if(a<0) return a+mod; return a; }
     23 
     24 int add (int a,int b) { a+=b; if(a>=mod) return a-mod; return a;}
     25 
     26 int qui (int a,int b)
     27 {
     28     int s=1;
     29     while(b)
     30     {
     31         if(b&1) s=1LL*s*a%mod;
     32         a=1LL*a*a%mod;
     33         b>>=1;
     34     }
     35     return s;
     36 }
     37 
     38 void NTT (int *f,int len,int v)
     39 {
     40     for (R i=0;i<len;++i) if(i<=rev[i]) swap(f[i],f[ rev[i] ]);
     41     int og,og1,t;
     42     for (R i=2;i<=len;i<<=1)
     43     {
     44         int ln=i>>1; og1=qui((v==1)?3:inv_g,(mod-1)/i);
     45         for (R b=0;b<len;b+=i)
     46         {
     47             og=1;
     48             for (R x=b;x<b+ln;++x)
     49             {
     50                 t=1LL*og*f[x+ln]%mod;
     51                 f[x+ln]=(f[x]-t+mod)%mod;
     52                 f[x]=(f[x]+t)%mod;
     53                 og=1LL*og*og1%mod;
     54             }
     55         }
     56     }
     57     if(v==-1)
     58     {
     59         int inv=qui(len,mod-2);
     60         for (R i=0;i<len;++i) f[i]=1LL*f[i]*inv%mod;
     61     }
     62 }
     63 
     64 void derivation (int *f,int *g,int len)
     65 {
     66     for (R i=1;i<len;++i) g[i-1]=1LL*f[i]*i%mod;
     67     g[len]=g[len-1]=0;
     68 }
     69 
     70 void integral (int *f,int *g,int len)
     71 {
     72     for (R i=0;i<len;++i) 
     73         g[i]=1LL*f[i-1]*inv[i]%mod;
     74     g[0]=0;
     75 }
     76 
     77 void mul (int *f,int *g,int len)
     78 {
     79     for (R i=0;i<len;++i) x[i]=y[i]=0;
     80     for (R i=0;i<len/2;++i) x[i]=f[i],y[i]=g[i];
     81     for (R i=1;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0);
     82     NTT(x,len,1); NTT(y,len,1);
     83     for (R i=0;i<len;++i) f[i]=1LL*x[i]*y[i]%mod;
     84     NTT(f,len,-1);
     85 }
     86 
     87 int read()
     88 {
     89     R x=0;
     90     char c=getchar();
     91     while (!isdigit(c)) c=getchar();
     92     while (isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
     93     return x;
     94 }
     95 
     96 void solve (int *f,int *a,int l,int r)
     97 {
     98     if(l==r)
     99     {
    100         f[0]=1; f[1]=a[l];
    101         return;
    102     }
    103     int mid=(l+r)>>1,ls=newpoly();
    104     solve(po[ls],a,l,mid);
    105     int rs=newpoly();
    106     solve(po[rs],a,mid+1,r);
    107     int len=1;
    108     while(len<=(r-l+1)) len<<=1;
    109     for (R i=0;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0);
    110     NTT(po[ls],len,1); NTT(po[rs],len,1);
    111     for (R i=0;i<len;++i) f[i]=1LL*po[ls][i]*po[rs][i]%mod;
    112     NTT(f,len,-1);
    113     sta[++tp]=ls; sta[++tp]=rs;
    114     for (R i=0;i<len;++i) po[ls][i]=po[rs][i]=0;
    115 }
    116 
    117 void Inv (int *a,int *b,int len)
    118 {
    119     if(len==1)
    120     {
    121         b[0]=qui(a[0],mod-2);
    122         return;
    123     }
    124     Inv(a,b,len>>1);
    125     for (R i=0;i<len*2;++i) x[i]=y[i]=0;
    126     for (R i=0;i<len;++i) x[i]=a[i],y[i]=b[i];
    127     for (R i=1;i<len*2;++i) rev[i]=(rev[i>>1]>>1)|((i&1)?(len):0);
    128     NTT(x,len<<1,1); NTT(y,len<<1,1);
    129     for (R i=0;i<len*2;++i)
    130         x[i]=1LL*x[i]*y[i]%mod*y[i]%mod;
    131     NTT(x,len<<1,-1);
    132     for (R i=0;i<len;++i)
    133         b[i]=dec(add(b[i],b[i]),x[i]);
    134 }
    135 
    136 int h[maxn],tt[maxn];
    137 
    138 void ln (int *f,int *g,int len)
    139 {
    140     derivation(f,g,len);
    141     for (R i=0;i<len;++i) h[i]=0;
    142     Inv(f,h,len);
    143     mul(g,h,len*2);
    144     integral(g,f,len);
    145 }
    146 
    147 int main()
    148 {
    149     scanf("%d%d",&n,&m);
    150     inv_g=qui(3,mod-2);
    151     for (R i=1;i<=n;++i) a[i]=read();
    152     for (R i=1;i<=m;++i) b[i]=read();
    153     scanf("%d",&t);
    154     inv[0]=inv[1]=1; 
    155     while(len<=max(n+m,t+t)) len<<=1;
    156     fac[0]=1; for (R i=1;i<=len;++i) fac[i]=1LL*fac[i-1]*i%mod;
    157     finv[len]=qui(fac[len],mod-2); for (R i=len;i>=1;--i) finv[i-1]=1LL*finv[i]*i%mod;
    158     for (R i=2;i<=len;++i) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
    159     solve(f,a,1,n); solve(g,b,1,m);
    160     memset(a,0,sizeof(a));
    161     memset(b,0,sizeof(b));
    162     ln(f,a,len); ln(g,b,len);
    163     for (R i=0;i<len;++i) f[i]=(i&1)?(1LL*f[i]*i%mod):(1LL*(mod-f[i])*i%mod);
    164     for (R i=0;i<len;++i) g[i]=(i&1)?(1LL*g[i]*i%mod):(1LL*(mod-g[i])*i%mod);
    165     f[0]=n; g[0]=m;
    166     for (R i=t+1;i<len;++i) f[i]=g[i]=0;
    167     for (R i=0;i<len;++i) f[i]=1LL*f[i]*finv[i]%mod,g[i]=1LL*g[i]*finv[i]%mod;
    168     for (R i=0;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0);
    169     NTT(f,len,1); NTT(g,len,1);
    170     for (R i=0;i<len;++i) f[i]=1LL*f[i]*g[i]%mod;
    171     NTT(f,len,-1);
    172     for (R i=1;i<=t;++i) printf("%lld
    ",1LL*f[i]*fac[i]%mod*inv[n]%mod*inv[m]%mod);
    173     return 0;
    174 }
    luogu-4705

      3.Codeforces Global Round 1;(这套题在计数器里贡献 $8$ )

      戳这里

      

      准备合格考导致很久没有 做 题 啊;

      不过现在我回来 做 题 了;

      这是这篇文章最后一次更新了,因为我又不AFO了,以后还是按月份写题解比较好,否则会不会一篇文章字数太多导致网站卡死?

      

      11.和与积:https://www.lydsy.com/JudgeOnline/problem.php?id=2671

      题意概述:给出 $n$,统计满足下面条件的数对$(a,b)$的个数,$n<2^{31}$:

      $1、1le a<b le n$

      $2、(a+b)|(a imes b)$

      这道题非常奇妙,乍一看毫无思路,但是(看了题解)就会发现也没有那么难。

    [$warning$:本题解思路混乱];

    这道题非常奇妙,乍一看毫无思路,但是~~(看了题解)~~就会发现也没有那么难。
    首先,看到这种整除类的题目就可以想到提取 $gcd$,按照这个思路把式子化一化:
    $$a=gp,b=gq$$
    $$g(p+q)|g^2pq$$
    $$(p+q)|gpq$$
    引理:若 $(a,b)=1$,则 $(a+b,ab)=1$;
    证明:$ecause (a,b)=1$
    $ herefore (a+b,b)=1~~~(a+b,a)=1$
    $ herefore (a+b,ab)=1$

    将这个引理用到之前的式子中去,就可以得到:
    $$(p+q)|g$$
    那么最终答案就是:
    $$sumlimits_{i=1}^nsumlimits_{j=i+1}^nsumlimits_{g=1}^n[(i,j)=g][frac{i+j}{g}|g]$$
    把 $g$ 提前:
    $$sumlimits_{g=1}^nsumlimits_{i=1}^{frac{n}{g}}sumlimits_{j=i+1}^{frac{n}{g}}[(i,j)=1][(i+j)|g]$$
    再把 $g$ 放回去?(思路混乱):
    $$sumlimits_{i=1}^{n}sumlimits_{j=i+1}^{n}[(i,j)=1][(i+j)|g]$$
    考虑对于确定的 $i,j$ ,直接算出有多少个符合条件的 $g$:
    $$sumlimits_{i=1}^{n}sumlimits_{j=i+1}^{n}[(i,j)=1]frac{n}{(i+j)}$$
    真的吗?假的;
    因为这个 $gcd$ 乘上 $i,j$ 还得满足小于等于 $n$,而上面一个式子并不能保证这一点;
    $$sumlimits_{i=1}^{n}sumlimits_{j=i+1}^{n}[(i,j)=1]frac{frac{n}{j}}{(i+j)}$$
    $$sumlimits_{i=1}^{n}sumlimits_{j=i+1}^{n}[(i,j)=1]frac{n}{j(i+j)}$$

  • 相关阅读:
    bootmgr is missing
    【转】ahci和IDE的区别
    win10系统故障代码:0xc000014c
    c++小数点后舍入
    关于类里再声明自身类实例的思考
    Java集合
    Python图片转字符画
    102. Binary Tree Level Order Traversal
    1041. Robot Bounded In Circle
    144. Binary Tree Preorder Traversal
  • 原文地址:https://www.cnblogs.com/shzr/p/10923932.html
Copyright © 2011-2022 走看看