A Eddy Walker
题意
有0…n-1,共n个点围成一圈,起点是0,给N和M,表示将所有点走完用了N步最后停在M点,求这种情况的概率。
思路
打表找规律,自定义一个圈的大小,算出在每个点停下的次数,大概推断出概率是1/(n-1)。
打表代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const ll mod = 1e9 + 7;
int vis[maxn], ans[maxn];
int main()
{
int n, pos, cnt;
scanf("%d", &n);
srand((time(0)));
for(int i = 1; i <= 100000; i++)
{
memset(vis, 0, sizeof(vis));
vis[0] = 1;
pos = 0;
cnt = 1;
while(cnt < n)
{
int moving = rand() % 2 ? 1 : -1;
pos = (pos + moving + n) % n;
if(!vis[pos])
{
vis[pos] = 1;
cnt++;
}
if(cnt == n)
{
ans[pos]++;
}
}
}
for(int i = 0;i < n; i++)
printf("%d ", ans[i]);
printf("\n");
return 0;
}
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const ll mod = 1e9 + 7;
ll qpow(ll a, ll b)
{
ll ans = 1;
a = a % mod;
while (b) {
if(b&1) ans = ans * a% mod;
a = a * a % mod;
b = b >> 1;
}
return ans;
}
int main()
{
int t;
cin >> t;
ll ans = 1;
while (t--) {
ll n, m;
cin >> n >> m;
if(n == 1 && m == 0) {
printf("%lld\n", ans);
continue;
}
else if(m == 0) {
ans = 0;
printf("%lld\n", ans);
continue;
}
printf("%lld\n", ans = ans * qpow(n - 1, mod - 2) % mod);
}
return 0;
}
F Partition problem
题意
2N个人,分成两队,求最大的total competitive value。
思路
暴力分组,但是会超时,所以还要加预处理。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 30 +7;
typedef long long ll;
int m, w[maxn][maxn];
ll sum[maxn][maxn], ans = 0;
int A;
void dfs(int x, int xx, ll v)//x表示选到第x个,xx表示选了xx个
{
if(xx == m) {
for (int i = 1; i < x; i++) {
if(A &(1<<i))
v += sum[i][2 * m] - sum[i][x - 1];
}
if(v > ans) ans = v;
return;
}
if(x - xx - 1 == m) {
for (int i = 1; i < x; i++) {
if(!(A&(1<<i)))
v += sum[i][2 * m] - sum[i][x - 1];
}
if(v > ans)
ans = v;
return;
}
//不选
ll t = 0;
for (int i = 1; i < x; i++) {
if(A&(1<<i)) t += w[i][x];
}
dfs(x + 1, xx, v + t);
//选
t = 0;
for (int i = 1; i < x; i++) {
if(!(A&(1<<i)))
t += w[i][x];
}
A|= 1<<x;
dfs(x + 1, xx + 1, v + t);
A &= ~(1<<x);
}
int main()
{
scanf("%d", &m);
for (int i = 1; i <= 2 * m; i++) {
for (int j = 1; j <= 2 * m; j++) {
scanf("%d", &w[i][j]);
}
}
for (int i = 1; i <= 2 * m; i++) {
for (int j = 1; j <= 2 * m; j++) {
sum[i][j] = sum[i][j - 1] + w[i][j];//预处理
}
}
A |= 1<<1;
dfs(2, 1, 0LL);
cout << ans << endl;
}
H Second Large Rectangle
题意
求不严格第二大矩形。
思路
悬线法加单调栈。
悬线法学习
论文:浅谈用极大化思想解决最大子矩形问题
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 7;
typedef long long ll;//g是原图 g[i][j] = 1表示所求的最大子矩形的组成元素
int g[maxn][maxn], h[maxn][maxn];
priority_queue<int, vector<int>, greater<int> > q;
void add(int x)
{
q.push(x);
while (q.size() > 2) q.pop();
}
int st[maxn];
int width[maxn];
int main()
{
int n, m;
int ans = 0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%1d", &g[i][j]);
h[i][j] = g[i][j] ? h[i - 1][j] + 1: 0;
}
h[i][m + 1] = 0;
}
q.push(0); q.push(0);
for (int i = 1; i <= n; i++) {
int top = 0;
for (int j = 1; j <= m + 1; j++) {
if(st[top] < h[i][j]) {
st[++top] = h[i][j];
width[top] = 1;
}
else {
int w = 0;
while (st[top] > h[i][j]) {
w += width[top];
add(st[top] * w);
add(st[top] * (w - 1));
add((st[top] - 1) * w);
top--;
}
st[++top] = h[i][j];
width[top] = w + 1;
}
}
}
printf("%d\n", q.top());
return 0;
}