• 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!}$还有一个限制条件是$sumlimits_{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
    ",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
    ");  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
    ",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
    ",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
    ");  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
    ",China());
    85     return 0;
    86 }
    AC
  • 相关阅读:
    C++基础学习6:内联函数
    lvm
    yum源
    mysql性能优化
    PXE
    dns配置
    进程命令
    ssh免密登陆和加密解密
    RAID阵列
    快速部署postfix邮件服务器
  • 原文地址:https://www.cnblogs.com/hzjuruo/p/11230720.html
Copyright © 2020-2023  润新知