AGC002 F - Leftmost Ball

29 篇文章 0 订阅

问题相当于计算有n个颜色0的球,其他n-1种颜色各有m-1个球,一个合法的序列是任意一个前缀中颜色0的球的数量>其他颜色的颜色数量

为了方便计数,我们不妨把每个颜色为0的球和一个颜色捆绑,即对于序列中(除了颜色0)出现的第i种颜色,我们将它捆绑到第i个颜色为0的球身上

然后可以设出一个dp,f[i][j][k]代表放了i个球,已经放了j个颜色为0的球,其他颜色已经出现了k种的方案数
状态数 O(n3k) O ( n 3 k ) ,转移 O(1) O ( 1 )

然后可以发现第一维i是没有必要的qaq
可以直接dp,f[i][j]表示放了i个颜色为0的球,其他颜色已经出现了k种的方案数
两种转移,放一个颜色为0的球和放一种颜色的所有球,组合数什么的算一下
状态数 O(n2) O ( n 2 ) ,转移 O(1) O ( 1 )

最后答案乘上 n! n ! 代表给颜色0的不同捆绑方案

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

const int maxn = 2000*2000+5;
const int mod  = 1e9+7;
inline void add(int &a,const int &b){a+=b;if(a>=mod)a-=mod;}

int pw(int x,int k)
{
    int re=1;
    for(;k;k>>=1,x=(ll)x*x%mod) if(k&1)
        re=(ll)re*x%mod;
    return re;
}
int inv(int x){ return pw(x,mod-2); }

int s[maxn],invs[maxn];
void pre()
{
    s[0]=1; for(int i=1;i<maxn;i++) s[i]=(ll)s[i-1]*i%mod;
    invs[maxn-1]=inv(s[maxn-1]);
    for(int i=maxn-2;i>=0;i--) invs[i]=(ll)invs[i+1]*(i+1)%mod;
}
int C(int n,int m){return (ll)s[n]*invs[m]%mod*invs[n-m]%mod;}

int n,m;
int f[2005];

int main()
{
    pre();

    scanf("%d%d",&n,&m); int u=n*m;
    if(m==1) return puts("1"),0;

    f[0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<i;j++)
            add(f[j+1],(ll)f[j]*C(u-i-j*(m-1)-1,m-2)%mod);
    }
    int ans=f[n];
    ans=(ll)ans*s[n]%mod;
    printf("%d\n",ans);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很高兴为您提供帮助!以下是一段可以生成任意简单多边形的代码: ```python import random def generate_polygon(num_vertices, min_coord, max_coord): # 生成随机的顶点坐标 vertices = [(random.randint(min_coord, max_coord), random.randint(min_coord, max_coord)) for i in range(num_vertices)] # 按照 x 坐标排序 vertices.sort() # 找到最左边的点和最右边的点 leftmost = vertices[0] rightmost = vertices[-1] # 将顶点分成上下两部分 uppers = [leftmost] lowers = [leftmost] for i in range(1, num_vertices): if i == num_vertices - 1 or (vertices[i][0] - leftmost[0]) * (rightmost[1] - leftmost[1]) > (rightmost[0] - leftmost[0]) * (vertices[i][1] - leftmost[1]): # 如果当前点在最左边的点和最右边的点之上,或者已经是最右边的点了,就将其加入上部分 while len(uppers) >= 2 and (vertices[i][0] - uppers[-2][0]) * (uppers[-1][1] - uppers[-2][1]) > (uppers[-1][0] - uppers[-2][0]) * (vertices[i][1] - uppers[-2][1]): uppers.pop() uppers.append(vertices[i]) elif (vertices[i][0] - leftmost[0]) * (rightmost[1] - leftmost[1]) < (rightmost[0] - leftmost[0]) * (vertices[i][1] - leftmost[1]): # 如果当前点在最左边的点和最右边的点之下,就将其加入下部分 while len(lowers) >= 2 and (vertices[i][0] - lowers[-2][0]) * (lowers[-1][1] - lowers[-2][1]) < (lowers[-1][0] - lowers[-2][0]) * (vertices[i][1] - lowers[-2][1]): lowers.pop() lowers.append(vertices[i]) # 将上下两部分连接起来 polygon = uppers + lowers[1:-1][::-1] return polygon # 生成一个 10 个顶点的简单多边形,坐标范围在 -100 到 100 之间 polygon = generate_polygon(10, -100, 100) print(polygon) ``` 这段代码使用了 Graham 扫描算法,可以生成任意简单多边形。具体实现过程可以参考这篇文章:https://www.geeksforgeeks.org/convex-hull-set-1-jarviss-algorithm-or-wrapping/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值