D 维空间里有一个关于点的集合 S,集合中的点的第 i 维坐标 ai 满足 1≤ai≤di ,其中 di 是给定的正整数 ,所以 S 中总共有 ∏di 个点。
定义一次空间旅行是指,从 (1,1,⋯,1) 开始进行移动,每次移动只能将某一维坐标加 1 、其他维坐标不变,从而走到下一个点,然后继续进行移动,每次移动前也可以选择结束此次旅行。
问至少进行多少次空间旅行,才能将 S 中所有的点都访问至少一次。
/*https://biancheng.love/contest-ng/index.html#/123*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <cstring>
#include <vector>
#include <string>
#include <stack>
#include <set>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
#define MP make_pair
#define PB push_back
typedef long long LL;
typedef pair<int, int> Pii;
const int inf = 0x3f3f3f3f;
const LL INF = (1uLL << 63) - 1;
const LL mod = 1000000007;
const int N = 1e5 + 5;
const double Pi = acos(-1.0);
const int maxn = 2e6 + 5;
int dp[25][maxn];
int sum[25][maxn];
int d[25];
int n , m;
int gao() {
dp[0][0] = 1;
/**
dp[i][j]表示在前i维内添加j所具有的状态数
dp[i][j] = sum(dp[i-1][k]) --------- 0 <= k <= j && j - k < di,di表示第i维的大小
dp[i-1][j]表示给第i维加上0,dp[i-1][j-1]表示给第i维加上1~~~~类推得dp[i-1][0]是给第i维的数字加上k
但是复杂度过高,用sum处理前缀和优化复杂度
所以
sum[i][j] = sum[i][j-1]+dp[i][j];
dp[i][j] = dp[i-1][j]+dp[i-1][j-1]+...+dp[i-1][j - di + 1] = sum[i-1][j] - sum[i-1][j - di];
**/
for(int i = 0; i <= m; i++)sum[0][i] = 1;
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= m; j++) {
if(j < d[i]) {
dp[i][j] = sum[i - 1][j];
}
else dp[i][j] = sum[i - 1][j] - sum[i - 1][j - d[i]];
sum[i][j] = (j ? sum[i][j - 1] : 0) + dp[i][j];
}
}
int res = 0;
for(int i = 0; i <= m; i++) {
res = max(dp[n][i], res);
}
return res;
}
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif
int cas;
cin >> cas;
while(cas--) {
/**
画一下从(1,1,1)作为根往下拓展的图可知
(d1,d2,...dn)的答案应该是这个图中某一层的结点个数最多的个数
!!! 可以把这个问题转化成
(1,1,1,1....),分配x个1到这上面,具有的状态最多
然后就是dp了。。
---------thx zk && from zk
**/
cin >> n;
m = - n;
for(int i = 1 ; i <= n ; i++) {
scanf("%d", &d[i]);
m += d[i];
}
cout << gao() << endl;
}
}
constroy 喜欢玩多米诺骨牌,他把若干块骨牌排列成一个 n 行 m 列的矩阵准备进行游戏。
但是 constroy 太笨了,他无法用一次触碰使所有的骨牌全部倒下。于是,他从第一行第一列的骨牌开始检查,依次检查第一行第二列,第一行第三列,……,第二行第一列,第二行第二列,……,第 n 行第 m 列的骨牌。如果他检查到一块骨牌没有倒下,那么他就会触碰它。而第 i 行第 j 列立着的骨牌被触碰时,有 pi,j 的概率向下一行倒,有 qi,j 的概率向下一列倒,并触碰该方向上与其相邻的骨牌(如果存在)。
请你估计一下笨拙的 constroy 总共触碰骨牌次数的期望值是多少吧。
提示:期望值是试验中每次可能结果的概率乘以其结果的总和。
这题。。。
注意是从左到右触碰骨牌还有骨牌只往下和往右倒。。。没注意这个样例都不会推。。。
本想求出触碰次数的概率。。然后再求期望。。但是这样太难。。
然后被教了一发,先考虑
每个骨牌要被触碰的概率,因为每个骨牌最多被触碰一次,所以他们的和也就是答案要求的期望
就是从整体拆成了每个点的样子=_=不知道怎么表述
但是好像博客里的邮票那题也是这样做的。。。我还是忘了啊啊啊
然后考虑每个点如果会被触碰,那么就是上方的点不往下倒&&左边的点也不往右倒,所以p = 1 - (pa + pb - pa*pb);
这是个概率公式= =实在不行画个两个相交的圆求(1 - 并集)也可以理解= =
/*https://biancheng.love/contest-ng/index.html#/123*/
#include <set>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#define mp make_pair
#define pb push_back
#define X first
#define Y second
using namespace std;
typedef long long LL;
const int maxn = 505;
int n, m;
double righ[maxn][maxn],down[maxn][maxn];
void init() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n,&m);
double ans = 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lf",&down[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lf",&righ[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
double t =1 - (down[i-1][j] + righ[i][j-1] - down[i-1][j]*righ[i][j-1]);
ans+=t;
}
printf("%.4lf\n",ans);
}
}
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
init();
return 0;
}
Tangjz 在二维平面上发现了 n 个互异的整点。
他很好奇,能否从中选出 m 个点恰好构成正多边形 (m≥3)(m≥3) 呢?
如果可以,请输出最大的 m ;如果不可以,请输出 -1 。
这题。。。因为点都是整点所以一定是正方形。。。想不到啊啊啊啊
所以就是判断m个点是否有正方形存在,剩下的就是枚举两点,再二分