退役后的做题记录

  ...

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

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

  计数器:10;

 

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

  

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

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

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

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

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

  $$\sum\limits_{i=0}^n\sum\limits_{j=0}^m\sum\limits_{k=0}^c\binom{n}{i}\binom{m}{j}\binom{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=\sum\limits_{i=0}^k\binom{k}{i}a^ib^{k-i}$

  显然可得:

  $(a+1)^k=\sum\limits_{i=0}^k\binom{k}{i}a^i$

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

  $\sum\limits_{i=0}^n\sum\limits_{k=0}^c\binom{n}{i}\binom{c}{k}(-1)^{n+m+c-i-k}\sum\limits_{j=0}^m\binom{m}{j}(-1)^j((k+1)^i)^j$

  $\sum\limits_{i=0}^n\sum\limits_{k=0}^c\binom{n}{i}\binom{c}{k}(-1)^{n+m+c-i-k}\sum\limits_{j=0}^m\binom{m}{j}((-k-1)^i)^j$

  $\sum\limits_{i=0}^n\sum\limits_{k=0}^c\binom{n}{i}\binom{c}{k}(-1)^{n+m+c-i-k}\sum\limits_{j=0}^m\binom{m}{j}1^{m-j}((-k-1)^i)^j$

  $\sum\limits_{i=0}^n\sum\limits_{k=0}^c\binom{n}{i}\binom{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$,二项式展开一下,就是:

  $\sum\limits_{x=1}^n\sum\limits_{y=1}^m\sum\limits_{i=0}^t\binom{t}{i}a_x^ib_y^{t-i}$

  $t!\sum\limits_{x=1}^n\sum\limits_{y=1}^m\sum\limits_{i=0}^t\frac{a_x^i}{i!}\frac{b_y^{t-i}}{(t-i)!}$

  $t!\sum\limits_{i=0}^t\frac{\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}^t\sum_{j=1}^na_j^ix^i$

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

  $f(x)=\sum_{i=1}^n\frac{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\n",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、1\le a<b \le n$

  $2、(a+b)|(a\times b)$

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

 

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

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

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

posted @ 2019-05-25 21:19  shzr  阅读(253)  评论(1编辑  收藏  举报