7.22T2

听学长讲了一波数论杂题,有点蒙,刚打完T3的模拟,决定早定写完T2题解,去磕T3的正解,不过事实上我T2没有A掉,只拿了WA60,你问我为什么没A敢写题解?因为我看了好久CRT,没看懂,所以决定有时间再打,先写一下T2的思路

30%

关于$30%t<=100$,空间和时间上$dp$都是可以承受的,用$dp[i][j][k]$代表在i时刻到达$(j,k)$这个点,其实很好想,每个点都有它上下左右的4个点转移而来,这个勤取模就可以了,不会被乱七八糟的模数为质为合干掉,不过我开始一直在$WA10$,还以为思路上有毛病,结果问过之后才知道,是可以走出$n*m$的格子的,这样的话边界就不能是$(n,m)$了,数组需要开大的同时,由于下标不能越界出负值,所以需要把所有的点向上,向右平移$t$个单位

60%

考试的时候我其实推出来了一部分式子,当时我以为都是那种很显然的废话,结果。。。。。。他是正解的来源,一开始看了一些题解,都没看懂,最后被WD大神解救了

先来一个导入,前几天学长讲线性基的时候WD有和secret聊过这个式子,且我觉得我听懂了,然而,我想不到,给你n种物品共k件,每种都分别有a1,a2,a3,a4,…,an件,求这k件物品本质不同的选择方案,很显然k个全排列就是$k!$但是内部那些一样的物品都被你当作不一样来用了,那就算多了,所以最后的结果是$\frac{k!}{a_1!*a_2!*a_3!*...*a_n!}$还有一个限制条件是$\sum\limits_{i=1}^{i<=n}a_i=k$

那回到这道题,我们设向左为$l$,向右为$r$,向上为$u$,向下为$d$,那么就会有

$r-l=n$  $u-d=m$  $l+r+u+d=t$

即$l+(n+l)+d+(m+d)=t$  移项得$2(l+d)=t-m-n$

证到这我们可以发现,如果$t-m-n$为奇数,那方案数就直接是0(说一个改题时候的小插曲,因为题目里说他可以在t时刻之前到达(n,m),我就以为他到了之后就不走了,结果就算你到达过,你也必须保证t时刻一定在(n,m),是我zz了)

转化一下问题,现在有4种走路选择共$k$步,第一种$l$步,第二种$r$步,第三种$d$步,第四种$u$步,这样的话就成功的转化成了导入里的那道题

如此一来我们就可以枚举$u$或$l$中的任意一个,用$Lucas$或者阶乘逆元直接算都没问题,可是这两种方法都只能解决模数为素数的时候,所以。。。。。

100%

合并$CRT$


 

A题后的补充

刚打完$CRT$,在让人抓狂的调代码中干掉了这道题,觉得有些东西不是一句合并$CRT$就可以解决的,关于$CRT$的话,记不住板子自己推一推,然而我死在了$Lucas$上

我在打60分代码的时候没有想到逆元可能全被干成0的情况,就是当$t<mod$的时候,因为我快速幂求的逆元所以会有这种情况,不知道为啥6个测试点都没卡我,然后就很抓狂了,我要把一个全是阶乘的式子变成C,原谅我没想出来,最后itawbm小姐姐解救了我,那个$t!$比上一堆东西,最后可以变成三个组合数相乘,$C_{2*a+n}^a*C_{2*b+m}^b*C_t^{2*a+n}$,我抄到算草纸上的时候抄错公式了,不停的WA0,结果还是因为zz,一开始$Lucas$也写错了,还调了半天,难受

T3正解还没看懂,估计明天又要考试了,也不知道能不能把题改完

 1 //可以走出n*m的网格,dp转移的话最远可以走到(-t,0),(t,0),(0,-t),(0,t)
 2 //这样的话数组最大需要dp[2*t+1][2*t+1],同时需要解决下标为负的问题
 3 //若解决下标为负,则应用(t,t)代替(0,0)作为起始点,才能保证数组不越界
 4 #include<iostream>
 5 #include<cstdio>
 6 #include<cmath>
 7 #define ll long long
 8 #define maxn 110
 9 using namespace std;
10 int t,n,m;
11 ll mod;
12 ll dp[maxn*2][maxn*2][maxn*2];
13 int main()
14 {
15     scanf("%d%lld%d%d",&t,&mod,&n,&m);
16     n=abs(n);  m=abs(m);
17     dp[0][t][t]=1;
18     for(int i=1;i<=t;++i)
19         for(int j=t-i;j<=t+i;++j)
20             for(int k=t-i;k<=t+i;++k)
21             {
22                 if(j-1>=0)  dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-1][k])%mod;
23                 if(k-1>=0)  dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k-1])%mod;
24                 dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+1][k])%mod;
25                 dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k+1])%mod;
26             }
27     printf("%lld\n",dp[t][n+t][m+t]%mod);
28     return 0;
29 }
30
 1 //可以走出n*m的网格,dp转移的话最远可以走到(-t,0),(t,0),(0,-t),(0,t)
 2 //这样的话数组最大需要dp[2*t+1][2*t+1],同时需要解决下标为负的问题
 3 //若解决下标为负,则应用(t,t)代替(0,0)作为起始点,才能保证数组不越界
 4 #include<iostream>
 5 #include<cstdio>
 6 #include<cmath>
 7 #define ll long long
 8 #define maxn 110
 9 #define maxx 100100
10 using namespace std;
11 int t,n,m;
12 ll mod,ans;
13 ll dp[maxn*2][maxn*2][maxn*2];
14 ll jc[maxx],ny[maxx];
15 ll ksm(ll a,ll b)
16 {
17     ll ans=1;  a=a%mod;
18     while(b)
19     {
20         if(b&1)  ans=(ans*a)%mod;
21         b=b>>1;  a=(a*a)%mod;
22     }
23     return ans;
24 }
25 int main()
26 {
27     scanf("%d%lld%d%d",&t,&mod,&n,&m);
28     n=abs(n);  m=abs(m);
29     if(((t-n-m)&1)!=0)  {printf("0\n");  return 0;}
30     if(t<=100)
31     {
32         dp[0][t][t]=1;
33         for(int i=1;i<=t;++i)
34             for(int j=t-i;j<=t+i;++j)
35                 for(int k=t-i;k<=t+i;++k)
36                 {
37                     if(j-1>=0)  dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-1][k])%mod;
38                     if(k-1>=0)  dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k-1])%mod;
39                     dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+1][k])%mod;
40                     dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k+1])%mod;
41                 }
42         printf("%lld\n",dp[t][n+t][m+t]%mod);
43     }
44     else
45     {
46         jc[0]=1;
47         for(int i=1;i<=t+1;++i)  jc[i]=(jc[i-1]*i)%mod;
48         ny[t+1]=ksm(jc[t+1],mod-2);
49         for(int i=t+1;i>=1;--i)  ny[i-1]=(ny[i]*i)%mod;
50         for(int a=0;a<=(t-m-n)/2;++a)
51         {
52             int b=(t-n-m)/2-a;
53             ll ls1=(jc[t]*ny[a])%mod;
54             ll ls2=(ls1*ny[b])%mod;
55             ll ls3=(((ls2*ny[n+a])%mod)*ny[m+b])%mod;
56             ans+=ls3;  ans=ans%mod;
57         }
58         printf("%lld\n",ans);
59     }
60     return 0;
61 }
60
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<vector>
 5 #define ll long long
 6 #define maxx 100100
 7 using namespace std;
 8 int t,n,m,cnt,p;
 9 ll ans;
10 ll jc[maxx],ny[maxx];
11 vector <ll> modd;
12 vector <ll> jg;
13 void shai(int y)
14 {
15     int x=sqrt(y);
16     for(int i=2;i<=x;++i)
17         if(y%i==0)  {modd.push_back((ll)i);  y=y/i;}
18     if(y!=1)  modd.push_back((ll)y);
19 }
20 ll ksm(ll a,ll b,ll c)
21 {
22     ll ans=1;  a=a%c;
23     while(b)
24     {
25         if(b&1)  ans=(ans*a)%c;
26         b=b>>1;  a=(a*a)%c;
27     }
28     return ans;
29 }
30 ll Lucas(int n,int m,ll mm)
31 {
32     if(n<m)  return 0;
33     if(n<mm&&m<mm)  return (((jc[n]*ny[n-m])%mm)*ny[m])%mm;
34     return (Lucas(n/mm,m/mm,mm)*Lucas(n%mm,m%mm,mm))%mm;
35 }
36 int exgcd(int a,int b,int &x,int &y)
37 {
38     if(b==0)  {x=1;  y=0;  return a;}
39     int gcd=exgcd(b,a%b,x,y);
40     int t=x;  x=y;  y=t-a/b*y;
41     return gcd;
42 }
43 ll China()
44 {
45     int x,y;  ll a=0,m,n=1;
46     for(int i=0;i<modd.size();++i)  n*=modd[i];
47     for(int i=0;i<modd.size();++i)
48     {
49         m=n/modd[i];
50         exgcd(modd[i],m,x,y);
51         a=(a+y*m*jg[i])%n;
52     }
53     if(a>0)  return a;
54     else  return a+n;
55 }
56 int main()
57 {
58     scanf("%d%d%d%d",&t,&p,&n,&m);
59     n=abs(n);  m=abs(m);
60     if(((t-n-m)&1)!=0)  {printf("0\n");  return 0;}
61     shai(p);
62     for(int i=0;i<modd.size();++i)
63     {
64         ll pp=modd[i],ans=0;
65         ll minnn=t;
66         jc[0]=1;
67         for(int j=1;j<=t;++j)
68         {
69             if(j>=pp)  {minnn=pp-1;  break;}
70             jc[j]=(jc[j-1]*j)%pp;
71         }
72         ny[minnn]=ksm(jc[minnn],pp-2,pp);
73         for(int j=minnn;j>=1;--j)  ny[j-1]=(ny[j]*j)%pp;
74         for(int a=0;a<=(t-m-n)/2;++a)
75         {
76             int b=(t-n-m)/2-a;
77             ll C1=Lucas(2*a+n,a,pp)%pp;  ll C2=Lucas(2*b+m,b,pp)%pp;
78             ll C3=Lucas(t,2*a+n,pp)%pp;
79             ll ls1=(C1*C2)%pp;  ll ls2=(ls1*C3)%pp;
80             ans+=ls2;  ans=ans%pp;
81         }
82         jg.push_back(ans);
83     }
84     printf("%lld\n",China());
85     return 0;
86 }
AC

 

posted @ 2019-07-23 11:26  hzoi_X&R  阅读(291)  评论(0编辑  收藏  举报