• noi online round2(入门组)


    又来了,第一题还是比较简单的,而且正好前面在弄最长不下降子序列的时候学到了二分的函数,lower_bound()和upper_bound的知识,刚好用上了,但是后面两个题目,第二题稍微写了下,但是越写越觉得不对。。第三题就一直放着,趁着写博客又来攻克一下吧~┭┮﹏┭┮脑壳不够用


    题目一:末了(真的挺简单的,我这种菜鸡还是能做出来心里还是很开心,不是零分了嘤)简单思路就是贪心加二分,没什么好说的,看代码应该就可以看懂,也可以比距离

    #include <bits/stdc++.h>
    using namespace std;
    const int N=200050,inf=0x3f3f3f;
    int a[N];
    double t[N],ask;
    int n,l,v,q;
    bool cmp(int x,int y) {return x>y;}
    int main()
    {
        cin>>n>>l>>v;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n,cmp);
        t[0]=l*1.0/(v*1.0);
        for(int i=1;i<=n;i++)
            t[i]=t[i-1]+a[i]*1.0/(v*1.0);
        cin>>q;
        for(int i=1;i<=q;i++){
            cin>>ask;
            if(ask>=t[n]){
                cout<<"-1"<<endl;continue;
            }
            cout<<upper_bound(t,t+n,ask)-t<<endl;
        }
        return 0;
    }

    题目二:荆轲刺秦王

     先来学习一下差分:

    从一个例子开始:将2~5区间内的每个数加上6

    原数组                    5 2 0 1 3 1 4

    修改后的数组          5 8 6 7 9 1 4

    原差分数组              5 -3 -2 1 2 -2 3

    修改后的差分数组   5 3 -2 1 2 -8 3

    我们可以发现,只有头和尾的差分会发生变化,并且变化规律为  a[l]+=k,(-3+6=3)  a[r+1]-=k;(-2-6=-8)

    可能对于差分的理解不够,还没有找到我特别能理解的差分的典型例子,找到了再来补一补吧

    但是大概能看懂代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,c1,c2,d;//如题
    int sx,sy,ex,ey;//起点终点坐标
    string s;//读入的数据
    int a[351][351];
    int flag[351][351];
    bool v[351][351][16][16];//剪枝二
    void add(int i,int j,int x){
        for(int k=-x+1;k<=x-1;k++){//差分使复杂度降为n^3
            if(k+i<1||k+i>n)continue;//超过边界 
            int p=x-1-(k<0?-k:k);//可以自己找规律
            if(j-p<1)a[k+i][0]+=1;
            else a[k+i][j-p]+=1;
            if(j+p+1>m);
            else a[k+i][j+p+1]-=1;
        }
    }
    struct zj{
        int x,y,u1,u2,t;//坐标,隐身使用次数,瞬移使用次数,已经过了多长时间
    };
    int ans1=0x3fffffff,ans2=0x3fffffff,ans=0x3fffffff;
    int X[8]={0,0,1,-1,1,1,-1,-1};
    int Y[8]={1,-1,0,0,1,-1,1,-1};
    void bfs(){
        queue<zj> q;
        q.push((zj){sx,sy,0,0,0});
        v[sx][sy][0][0]=1;//起点已经过
        while(!q.empty()){
            zj x=q.front();
            q.pop();
            if(x.t>ans)continue;//剪枝一
            if(x.x==ex&&x.y==ey){
                if(x.t<ans){
                    ans=x.t;
                    ans1=x.u1;
                    ans2=x.u2;
                }
                else{
                    if(ans1+ans2>x.u1+x.u2){//魔法使用次数少
                        ans=x.t;
                        ans1=x.u1;
                        ans2=x.u2;
                    }
                    else if(ans1+ans2==x.u1+x.u2&&ans1>x.u1){//魔法一样,隐身少
                        ans=x.t;
                        ans1=x.u1;
                        ans2=x.u2;                    
                    }
                }
                continue;
            }
            for(int i=0;i<8;i++){
                int xx=x.x+X[i],yy=x.y+Y[i];
                if(xx<1||xx>n||yy<1||yy>m)continue;//越界
                if(flag[xx][yy]==1)continue;//有士兵
                if(a[xx][yy]<=0&&v[xx][yy][x.u1][x.u2]==0){//不在士兵的观察范围内
                    v[xx][yy][x.u1][x.u2]=1;//标记
                    q.push((zj){xx,yy,x.u1,x.u2,x.t+1});
                }
                else if(x.u1+1<=c1&&v[xx][yy][x.u1+1][x.u2]==0){//在士兵的观察范围内,使用隐身
                    v[xx][yy][x.u1+1][x.u2]=1;//标记
                    q.push((zj){xx,yy,x.u1+1,x.u2,x.t+1});
                }
            }
            if(x.u2+1>c2)continue;//无法使用瞬移
            for(int i=0;i<4;i++){
                int xx=x.x+X[i]*d,yy=x.y+Y[i]*d;
                if(xx<1||xx>n||yy<1||yy>m)continue;
                if(flag[xx][yy]==1)continue;
                if(a[xx][yy]<=0&&v[xx][yy][x.u1][x.u2+1]==0){
                    v[xx][yy][x.u1][x.u2+1]=1;
                    q.push((zj){xx,yy,x.u1,x.u2+1,x.t+1});
                }
                else if(x.u1<c1&&v[xx][yy][x.u1+1][x.u2+1]==0){
                    v[xx][yy][x.u1+1][x.u2+1]=1;
                    q.push((zj){xx,yy,x.u1+1,x.u2+1,x.t+1});
                }
            }
        }
    }
    int main(){
        scanf("%d%d%d%d%d",&n,&m,&c1,&c2,&d);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>s;
                if(s=="S")flag[i][j]=-2,sx=i,sy=j;//记录起点位置 
                else if(s=="T")flag[i][j]=-1,ex=i,ey=j;//记录终点位置 
                else if(s==".");
                else{
                    flag[i][j]=1;
                    int x=s[0]-'0';
                    for(int i=1;i<s.length();i++)x=x*10+s[i]-'0';//存入卫兵可以观察的距离 
                    add(i,j,x);//处理 
                }
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                a[i][j]+=a[i][j-1];//注意差分要加回去
            }
        }
        bfs();
        if(ans==0x3fffffff)printf("-1");//无解
        else printf("%d %d %d",ans,ans1,ans2);//输出
        return 0;
    }
    View Code

     为什么用自己当时的做法结合一下只能得八十分呢~好奇怪,最容易错的反而没有错:

    #include <bits/stdc++.h>
    using namespace std;
    const int N=405,inf=0x3f3f3f3f;
    int n,m,c1,c2,s,a[N][N],sol[N][N],vis[N][N][20][20];
    int d[8][2]={{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
    int sx,sy,ex,ey,ans=inf,ans1=inf,ans2=inf;
    struct node{
        int x,y,c1,c2,num;
    };
    void pre(int x,int y,int dis,int step)//标记士兵范围的区域 
    {
        int rx,ry;
        if(step==dis) return;
        else{
            for(int i=0;i<4;i++){
                rx=x+d[i][0];
                ry=y+d[i][1];
                if(!sol[rx][ry]&&!a[rx][ry]&&rx>=1&&rx<=n&&ry>=1&&ry<=m){
                    a[rx][ry]=1;//表示在士兵范围内 
                    pre(rx,ry,dis,step+1);
                }
            }
        }
    }
    int num(string s)
    {
        int ans=0;
        for(int i=0;i<s.length();i++)
            ans=ans*10+s[i]-'0';
        return ans;
    }
    void bfs()
    {
        queue<node> q;
        q.push((node){sx,sy,0,0,0});
        vis[sx][sy][0][0]=1;
        while(!q.empty())
        {
            node p=q.front();q.pop();
            if(p.num>ans) continue;//剪枝
            if(p.x==ex&&p.y==ey){
                if(p.num<ans){ans=p.num;ans1=p.c1;ans2=p.c2;}
                else{
                    if(p.c1+p.c2<ans1+ans2){ans=p.num;ans1=p.c1;ans2=p.c2;}
                    else if(p.c1+p.c2==ans1+ans2&&ans1>p.c1){ans=p.num;ans1=p.c1;ans2=p.c2;}
                }
                continue;
            }
            for(int i=0;i<8;i++){
                int rx=p.x+d[i][0],ry=p.y+d[i][1];
                if(rx<1||rx>n||ry<1||ry>m) continue;//越界
                if(sol[rx][ry]>0) continue;//有士兵
                if(!a[rx][ry]&&!vis[rx][ry][p.c1][p.c2]){//不在士兵的观察范围内并且没有访问过 
                    vis[rx][ry][p.c1][p.c2]=1;//标记
                    q.push((node){rx,ry,p.c1,p.c2,p.num+1});
                }
                else if(p.c1+1<=c1&&!vis[rx][ry][p.c1+1][p.c2]){//在士兵的观察范围内,使用隐身
                    vis[rx][ry][p.c1+1][p.c2]=1;//标记
                    q.push((node){rx,ry,p.c1+1,p.c2,p.num+1});
                }
            }//只使用隐身或者直接走的情况
            if(p.c2+1>c2) continue;//已经不能使用瞬移就直接结束
            for(int i=0;i<4;i++) 
            {
                int rx=p.x+d[i][0]*s,ry=p.y+d[i][1]*s;
                if(rx<1||rx>n||ry<1||ry>m) continue;//越界
                if(sol[rx][ry]>0) continue;//有士兵
                if(!a[rx][ry]&&!vis[rx][ry][p.c1][p.c2+1]){//不在士兵的观察范围内并且没有访问过 
                    vis[rx][ry][p.c1][p.c2+1]=1;//标记
                    q.push((node){rx,ry,p.c1,p.c2+1,p.num+1});
                }
                else if(p.c1+1<=c1&&!vis[rx][ry][p.c1+1][p.c2+1]){//在士兵的观察范围内,额外使用隐身
                    vis[rx][ry][p.c1+1][p.c2+1]=1;//标记
                    q.push((node){rx,ry,p.c1+1,p.c2+1,p.num+1});
                }
            }
        }
    }
    int main()
    {
        //cin>>n>>m;
        //pre(3,3,3,1); 
        scanf("%d %d %d %d %d",&n,&m,&c1,&c2,&s);
        string c;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                cin>>c;
                if(c[0]=='S') {sol[i][j]=-1;sx=i;sy=j;}
                else if(c[0]=='T'){sol[i][j]=-2;ex=i;ey=j;}
                else if(c[0]>='0'&&c[0]<='9'){
                    sol[i][j]=num(c);
                    pre(i,j,sol[i][j],1);
                } 
            }
        bfs();
        
        if(ans==inf)printf("-1");//无解
        else printf("%d %d %d",ans,ans1,ans2);//输出
        /*
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                cout<<a[i][j]<<" ";
            cout<<endl;
        }
        cout<<endl;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                cout<<sol[i][j]<<" ";
            cout<<endl;
        }
        */
        //dfs(sx,sy,0,0,0);
        return 0;
    }
    View Code

     来了,找到原因了,补充来了:

    用dfs或者bfs处理曼哈顿距离(正确做法75分(tle) 错误做法反而能得80分(wa))

    处理最短时间的代码都是一样的,唯一不同的就是处理曼哈顿距离这里:

     dfs:

    void pre(int x,int y,int dis,int step)//标记士兵范围的区域 
    {
        int rx,ry;
        if(step==dis) return;
        for(int i=0;i<4;i++){
            rx=x+d[i][0];
            ry=y+d[i][1];
            if(sol[rx][ry]<=0&&rx>=1&&rx<=n&&ry>=1&&ry<=m){//错误做法就是加上一个条件!a[rx][ry] 能得80分 
                a[rx][ry]=1;//表示在士兵范围内 
                pre(rx,ry,dis,step+1);
            }
        }
    }

    bfs:

    void pre(int x,int y,int dis,int step) 
    {
        queue<obs> q;int rx,ry;//还有可能超空间 
        q.push((obs){x,y,step});
        while(!q.empty())
        {
            obs p=q.front();q.pop();
            if(p.step==dis) continue;
            for(int i=0;i<4;i++){
                rx=p.x+d[i][0];
                ry=p.y+d[i][1];
                if(sol[rx][ry]<=0&&rx>=1&&rx<=n&&ry>=1&&ry<=m){
                    a[rx][ry]=1;//表示在士兵范围内 
                    q.push((obs){rx,ry,p.step+1});
                }
            }
        }
    }

    题目三:建设城市(分为四段,1-i i+1-n n+1-j j+1-2n

    dp[i][j]:长度为i,末尾为j的单调递增的序列个数

    dp[i][j]=Σk=1jdp[i-1][k];

    优化:也可以状态转移为:dp[i][j]表示长度为i,末尾<=j的单调递增序列,d[i][j]=dp[i][j-1]+dp[i-1][j]   60分

    继续优化:排列组合的插板?~dp[i][j]=C(i+j-1,i)=(i+j-1)!/i!(j-1)!

    线性求阶乘逆元优化    100分

    好吧:又来学习一下做这个题目应该掌握的预备知识了

    来了,第一步:如果没有第5个要求的话,那么,我们只来看一看左边上升部分有多少种情况呢?我们有n栋楼,所有楼的高度范围为(1-m),那么我们可以把这个模型抽象为有n个球,现在把它们放入m个盒子中(编号就为1-m,在在哪个盒子就高度是多少,可以相同),所以我们就是允许有些盒子为空的,那么我们就根据插板法:

    总结:

    1:如果是把n个求放入k个盒子中(每个盒子必须要有球),那么由插板法得 方案数为 C(n-1,k-1);

    2:如果是把n个求放入k个盒子中(盒子可以为空),那么由插板法得 方案数为 C(n+k-1,k-1);我们很显然是这个情况~(get it)

     第二步:那么我们现在要把第5个要求加进来的话,现在就有两种情况了,x/y在两侧还是同侧,我们先枚举这两栋楼高度为i

    1、在两侧的话:

    x左边的x栋楼高度范围为(1-i);x右边到n左边(包括n)n-x栋楼的高度范围为(i,m);

    n右边(不包括n)到y左边y-n-1栋楼的高度范围为(i,m);y右边的2n-y栋楼的高度范围为(1-i)

    就把四种情况乘起来就是答案了

    2、如果在一侧的话:就把x,y之间的高楼看成一个高楼

    就有c(n+m-1,m-1)*c(n+x-y+m-1,m-1);

    又有问题来了:我们知道c(n+m-1,m-1)=(n+m-1)!/(m-1)!*n!

    就有乘法的逆元:

    (a+b)%p=(a%p+b%p)%p

    (a-b)%p=(a%p-b%p)%p

    (a*b)%p=(a%p*b%p)%p

    但是(a/b)%p!=(a%p/b%p)%p;除法不满足我们的分配律,但我们也需要在这个过程中去模,否则中间值会出现太大的情况,所以我们要用到乘法逆元:

    乘法逆元一般用于求a/b(mod)p的值,是解决模意义下分数值的必要手段。

    逆元定义:若a*x=1(mod b),且a与b 互斥,那么我们就能定义x为a的逆元,记为a-1,所以我们也可以称x为a在mod意义下的倒数。所以对于a/b(mod p) ,我们就可以求出 b 在mod p 下的逆元,然后乘上 a ,再 mod p就是这个分数的值了。。。没太看懂,举例,5和14是互斥的,所以就存在5关于模14的乘法逆元为3,3*5-14=1;

    可以看成一个公式就是ax-pb=1,把减号变成加号,所以有一个公式就变成:ax+by=1;,然后可以扩展欧几里得定理来扩展了。

    应用(求取(a/b)%p等同于求取a*(b的逆元)%p)

    证明:

     那么问题又来了,怎么去求解乘法的逆元是多少呢?方法很多种:费马小定理(p为质数)、扩展欧几里得、线性递推......

    费马小定理:假如a是一个整数,p是一个质数,那么

    1、如果a是p的倍数 a^p=a(mod p)

    2、如果a不是p的倍数,a^(p-1)=1(mod p)    乘法逆元中要求互斥,所以肯定不是倍数

    同余式:a=b(mod n)表示a和b对模n同余,即正整数a-b能被n整除

    所以   a*a^(p-2)=1 (mod p)那么a^(p-2) 就是 a 的逆元了~

    但是需要注意:上面都不是等号,有(mod p)的这种都是同余符号,三个横线;所以这个式子完整的应该是(a%p)*(a^(p-2))%p=1%p,这才是等式

    例如:a=5,p=3;那么a的逆元就是 5^(3-2)%3=2;,所以在这里就可以也可以用快速幂进行优化;

    ll fpm(ll x,ll power,ll mod)//x^power%mod就是要求的逆元 
    {
        x%=mod;
        ll ans=1;
        for(;power;power>>=1,(x*=x)%=mod)
            if(power&1) (ans*=x)%=mod;
        return ans; 
    }

    ****求一串数字的逆元可以用线性算法,代码过背吧...

    ll inv[maxn]={0,1};
    int main(){
        int n,p;
        scanf("%d%d",&n,&p);
        printf("1
    ");
        for(int i=2;i<=n;i++)
            inv[i]=(ll)p-(p/i)*inv[p%i]%p,printf("%d
    ",inv[i]);
        return 0;
    }

    那么整个题目的分析应该就完了

    最后再来总结一下这个题目,

    首先我们清楚了n栋楼房在高度范围为<=m的所有排列情况,因为可以为空所以一共有c(n+m-1,m-1)种方案;

    然后我们加上限制条件5,两种情况:一种四段相乘,一种两段相乘 

    然后我们知道c(m+n-1,m-1)=(m+n-1)!/n!*(m-1)!,由于数会很大,所以我们需要模p,但是除法不满足分配律,我们利用乘法逆元把它变成乘法的模,就可以防止中间数会很大溢出;

    我们知道要用乘法逆元之后,选择求出逆元的方法有很多,这里用费马小定理,那么我们在求的时候还可以加上快速幂,那么关于

    over!下面就来看代码了~(好吧,尽量理解了)

     !!!!!!!!我感觉思路没有什么问题,但答案就是不对。。。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=998244353;
    ll ans=0;
    int n,m,x,y;
    ll fpm(int num,int power)//x^power%mod就是要求的逆元 
    {
        num%=mod;
        ll res=1;
        for(;power;power>>=1,(num *= num) %=mod)
            if(power&1) (res *= num) %=mod;
        /*应该就是快速幂 
        for(;power;power>>=1,(x*=x)%=mod)
            if(power&1) (ans*=x)%=mod;
        */
        return res; 
    }
    ll c(int a,int b)
    {
        ll sum=1;
        for(int i=1;i<=b;i++)
        {
            sum=sum%mod*(a-b+i)%mod;
            sum=sum%mod*fpm(i,mod-2)%mod;
        } 
        return sum;
    }
    int main()
    {
        cin>>m>>n>>x>>y;
        if(x<=n&&y>=n)//在两侧的情况
        {
            for(int i=1;i<=m;i++)//枚举相等的两栋楼的情况
                //ans=(ans+((ll)f(x-1,i)*f(n-x,m-i+1)%mod*f(y-n-1,m-i+1)%mod*f(n*2-y,i)%mod))%mod;
                ans+=c(x+i-1,i-1)%mod*c(n-x+m-i,m-i)%mod*c(y-n+m-i,m-i)%mod*c(2*n-y+i-1,i-1)%mod;
        } 
        else 
        {
            //ans=(ll)c(n+m,m)*c(x+n-y+m,m)%mod;
            ans=c(n+m-1,m-1)%mod*c(n+m-1-x+y,m-1)%mod;
        }
        cout<<ans<<endl;
        return 0;
    }
    有问题

    有人知道就评论一下吧,所以现在换一个做法,其实思路差不多就是划分的区域和代码有点出入。

    划分区域:1x1,x+1n,n+1y1,y+1n2

    那么就是f(i,j)=(i+j-1)!/(j-1)!*i!

    所以先进行预处理求出相关的逆元与阶乘,所以就可以用到线性逆元的方法,前面也写了,直接记住也可以:

    #include<bits/stdc++.h>
    #define ll long long
    #define mod 998244353
    using namespace std;
    const int N=200001;
    int n,m,x,y;
    ll k[N],inv[N],invk[N];
    ll ans=0;
    ll f(ll a,ll b)
    {
        return (ll)(k[a+b-1]*invk[a]%mod*invk[b-1]%mod);
    }
    
    int main(){
        scanf("%d%d%d%d",&m,&n,&x,&y);
        k[0]=inv[1]=invk[0]=1;
        for(int i=2;i<=n+m;i++) inv[i]=((ll)mod-mod/i)*inv[mod%i]%mod;//处理1到n的逆元
        for(int i=1;i<=n+m;i++) k[i]=(ll)k[i-1]*i%mod;//处理阶乘
        for(int i=1;i<=n+m;i++) invk[i]=(ll)invk[i-1]*inv[i]%mod;//处理阶乘数组的逆元
        if(x<=n&&y>n){
            for(int i=1;i<=m;i++) ans=(ans+(ll)(f(x-1,i)*f(n-x,m-i+1)%mod*f(y-n-1,m-i+1)%mod*f(n*2-y,i)%mod))%mod;
            printf("%lld",ans);
        }
        else{
            printf("%lld",(ll)f(n,m)*f(x+n-y,m)%mod);
        }
        return 0;
    }
    View Code

     在来简单版的讲解:

    一道关于排列组合的数学题

    首先有五个条件,先不看第五个条件,没有x,y高度相等这个条件

    那么就直接看n座楼,他们的高度范围是[1-m],抽象为n个球放入到m个盒子中

    数学中是这样来做的:

    1:如果是把n个球放入k个盒子中(每个盒子必须要有球),那么由插板法得方案数为 C(n-1,k-1);

    2:如果是把n个球放入k个盒子中(盒子可以为空),那么由插板法得 方案数为 C(n+k-1,k-1);

    这个题目显然就是第二种情况;

    现在又加上条件五的话,我们就可以把这个分成两种情况:

    1、x,y在同侧

    那么一侧为 n个球 m个盒子 我们写成f(n,m)

    有x,y在的一侧,x-y的高度是相同的,我们把这一段看成一个整体 就相当于f(n+y-x,m)

    2、x,y在两侧

    就分成四段 1-x-1 x+1-n n+1-y-1 y+1-2*n

    去枚举x,y的高度i

    这四段就相当于 f(x-1,i) f(n-x,m-i+1) f(y-n-1,m-i+1) f(n*2-y,i)

    答案就是他们相乘

    但是f(i,j)=c(i+j-1,j-1)=(i+j-1)!/(j-1)!i!

    除法不满足分配率,不能取余,但是中间数可能会很大,所以就要用到乘法逆元

    证明过程省去,知道两点:

    1、(a/b) %p 等于 (a*b的逆元)%p

    2、费马小定理得出 b的逆元为 b^p-2 (快速幂)

    #include<bits/stdc++.h>
    #define ll long long
    #define mod 998244353
    using namespace std;
    const int N=200001;
    int n,m,x,y;
    ll k[N],inv[N],invk[N];
    ll ans=0;
    ll f(ll a,ll b)
    {
        return (ll)(k[a+b-1]*invk[a]%mod*invk[b-1]%mod);
    }
    ll quickpow(ll a,int b){//快速幂写法一 
    
        if(b==1) return a;
        ll res=(ll)quickpow(a,b>>1);
        if(b%2==1) return (ll)res*res%mod*a%mod;
        else return (ll)res*res%mod;
    }
    /* 
    ll quickpow(ll a,int b){//快速幂写法二 
        ll res=1;
        while(b)
        {
            if(b&1) res=(ll)res*a%mod;
            a=(ll)a*a%mod;
            b>>=1;
        }
        return res;
    }*/
    int main(){
        scanf("%d%d%d%d",&m,&n,&x,&y);
        k[0]=invk[0]=1;
        for(int i=1;i<=n+m;i++) k[i]=(ll)k[i-1]*i%mod;//处理阶乘
        for(int i=1;i<=n+m;i++) invk[i]=(ll)quickpow(k[i],mod-2);//处理阶乘数组的逆元
        if(x<=n&&y>n){
            for(int i=1;i<=m;i++) ans=(ans+(ll)(f(x-1,i)*f(n-x,m-i+1)%mod*f(y-n-1,m-i+1)%mod*f(n*2-y,i)%mod))%mod;
            printf("%lld",ans);
        }
        else{
            printf("%lld",(ll)f(n,m)*f(x+n-y,m)%mod);
        }
        return 0;
    }
    View Code

    好吧下一次的noi online 又要来了,慌张。。。

  • 相关阅读:
    生成文件的MD5文件
    磁场动 电子不动, 有 洛伦兹力 吗 ?
    牛顿水桶 的 水面凹陷 和 变轻 就是 个 离心力, 大家 这么 慌乱 干什么 ?
    《【竞价】宏观微观统一量子化波动方程》 回复
    一些有意义的课题 : 氢原子光谱 氢原子电子云 小孔衍射 双缝干涉
    调和级数 和 双盲测试
    webrtc降噪原理
    关于浏览器显示的图片点击下载
    Windows 下如何添加和删除服务
    领域驱动设计知识语境、限界上下文、领域
  • 原文地址:https://www.cnblogs.com/sunny99/p/12790071.html
Copyright © 2020-2023  润新知