2021-08-22

5 篇文章 0 订阅

Add or Multiply 1
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 150 Accepted Submission(s): 36

Problem Description
前两段和第五题相同,但你不需要阅读第五题就可以完成这个题目。

你有一个数字 x 和若干个操作,每个操作是 +ai 或者乘 ×ai 中的一种。你可以重新排列这些操作的顺序,然后对数字 x 执行这些操作。

比如说三个操作是 +a1,+a2,×a3。如果按顺序执行这三个操作,那么得到的结果是 ((x+a1)+a2)×a3。如果排列成 +a2,×a3,+a1,那么得到的结果是 ((x+a2)×a3)+a1。

我们会发现,有一些操作顺序计算出来的结果是本质相同的,比如说+a1,+a2,×a3和+a2,+a1,×a3这样运算下来结果是一样的。我们认为两个操作顺序计算的结果本质相同,当且仅当无论代入什么数,计算出来的结果都是一样的。

请问有多少种本质不同的操作序列。换句话说就是最多能找到多少个操作序列,使得这些操作序列任意两个都不是本质相同的。由于答案很大,输出对109+7取模的结果。

在这个题目中,我们只会给出加法操作和乘法操作的个数,分别是n,m,并不会给出具体的顺序和数字。容易发现,答案与具体的顺序和数字无关。

Input
本题有多组测试数据。

第一行一个整数 T(1≤T≤104) 表示数据组数。

对于每组数据,一行两个整数 n,m(1≤n,m≤3000) 描述一组询问,表示操作中加法个数和乘法个数。

Output
对于每组数据输出一行,表示答案。

Sample Input
3
2 1
5 5
100 100

Sample Output
4
329462
294770659

Source
2021 年百度之星·程序设计大赛 - 复赛

很显然,连续的加号和乘号之间交换顺序是本质相同的运算,所以题目可以转换成将加号和乘号进行分组,由于他们的组之间是相互分割的,所以组数之差不超过1,也就是说有三种情况:
1、加号比乘号组数多一个,此时只有一种情况也就是 +×+
2、乘号比加号组数多一个,此时也只有一种情况也就是 ×+×
3、加号和乘号组数一样多,此时有两种情况,也就是×+×+和+×+×
所以我们穷举其中一个的组数,然后分类讨论另一种组数即可。
那么如何求出分组的情况呢,我们用ans[i] [j]表示将i个物品分成j组(组内顺序无关但是组间顺序有关),考虑递推求解。将i个物品分成j组可以转换成将i个物品放入j个盒子中且每个盒子至少有一个物品。ans[i-1] [j]表示当前已经将i-1个物品放入了j个盒子中,需要将最后一个物品放入盒子中,那么现在有两种情况:
1、当前还剩一个空盒子,也就是说当前将i-1个物品放入了j-1个盒子中得到情况数为ans[i-1] [j-1],此时最后一个物品必须放入这个空盒子中(否则情况不合法,若有两个及以上的空盒子也不合法),此时也就是ans[i-1] [j-1]*1。
2、没有空盒子,也就是当前的情况数为ans[i-1] [j],那么最后一个物品可以放在任意一个盒子,也就是有j种选择,所以这种情况得到的方案数为
ans[i-1] [j]×j。
ans[0][0]显然是1,ans[i][1]也显然是1(只放入一个盒子当然只有一种情况)。于是我们就可以预处理得到所有情况的方案数。
接下来看代码吧

#include<cstdio>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<unordered_map>
#include<string>
#include<queue>
#include<map>
#include<ctime>
#include<limits.h>
#include <stack>
#include<set>
#include<iomanip>
#define ll long long
#define int long long
#define um unordered_map
#pragma warning(disable : 4996)
using namespace std;
#define rep(l,a,b) for(ll l=a;l<=b;l++)
#define repp(l,a,b) for(ll l=a;l>=b;l--)
#define mem(x) memset(x,0,sizeof(x))
#define fr fast_IO::read()
#define INF 0X3f3f3f3f
namespace fast_IO {
	ll read() {
		ll num = 0;
		char c;
		bool tag = false;
		while ((c = getchar()) != '-' && c != '+' && (c < '0' || c > '9') && ~c);
		if (!~c)return EOF;
		if (c == '-')tag = true;
		else if (c == '+')tag = false;
		else num = c ^ 48;
		while ((c = getchar()) >= '0' && c <= '9')
			num = (num << 1) + (num << 3) + (c ^ 48);
		if (tag)return -num;
		return num;
	}
}
//--------------------------------------------------------------
const int mod = 1e9 + 7;
#define N 6005
int n, m, k;
ll mul[N];
ll cc[N][N];
int ans[N][N], jie[N];//把i个操作分成j组的方案

void init()
{
	jie[0] = 1;//预处理阶乘
	for (int i = 1; i <= 3000; ++i) ans[i][1] = 1, jie[i] = jie[i - 1] * i % mod;
	for (int i = 2; i <= 3000; ++i)//预处理方案数
		for (int j = 2; j <= i; ++j)
			ans[i][j] = (ans[i - 1][j - 1] + ans[i - 1][j] * j % mod) % mod;
	for (int i = 2; i <= 3000; ++i)//对组间进行全排序
		for (int j = 2; j <= i; ++j)//所以要乘上j!
			ans[i][j] = ans[i][j] * jie[j] % mod;
}
signed main()
{
	//freopen("in.txt", "r", stdin);
	init();
	int t;
	cin >> t;
	while (t--)
	{
		n = fr, m = fr;
		ll res = 0;
		rep(i, 1, n)//穷举组数
		{//对应上面所说的三种情况,因为ll最大有2e19,所以取两次模即可,取模运算可是很慢的
			res = (res + ans[n][i] * (ans[m][i - 1] + 2 * ans[m][i] + ans[m][i + 1]) % mod) % mod;
		}
		printf("%lld\n", res);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用python中的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值