week2训练补题(济南+上海区域赛)

上海站

C题是典型的数位DP,我把这道题做出来之后才去开了济南的L
大概就是用两个布尔维度表示一下是否卡上界,然后做一下记忆化搜索

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int t, X, Y;
const int maxn = 32;
const ll mod = 1e9 + 7;
int xx[maxn], yy[maxn];
int lx, ly;
ll dp[maxn][2][2];

ll solve(int p, bool x, bool y)
{
	if (p == -1)
		return 1ll;
	if (dp[p][x][y] != -1)
		return dp[p][x][y];
	int xlim = x ? 1 : xx[p];
	int ylim = y ? 1 : yy[p];
	ll ans = 0;
	for (int i = 0; i <= xlim; ++i)
	{
		for (int j = 0; j <= ylim; ++j)
		{
			if (i & j)
				continue;
			ans += solve(p - 1, x | (i < xlim), y | (j < ylim));
			ans %= mod;
		}
	}
	dp[p][x][y] = ans;
	return ans;
}

int i2v(int n, int *v)
{
	int i = -1;
	for (; n; n >>= 1)
	{
		i++;
		v[i] = n & 1;
	}
	return i;
}

int main()
{
	// freopen("cin", "r", stdin);
	for (scanf("%d", &t); t--;)
	{
		memset(dp, -1, sizeof(dp));
		memset(xx, 0, sizeof(xx));
		memset(yy, 0, sizeof(yy));
		scanf("%d%d", &X, &Y);
		lx = i2v(X, xx);
		ly = i2v(Y, yy);
		ll ans = 0;
		for (int i = 0; i <= lx; ++i)
			ans = (ans + solve(i - 1, i < lx, i <= ly) * (i + 1)) % mod;
		for (int j = 0; j <= ly; ++j)
			ans = (ans + solve(j - 1, j <= lx, j < ly) * (j + 1)) % mod;
		printf("%lld\n", ans);
	}
	return 0;
}

I题是道计数,场上那会儿被特判卡了没A出来
参考逆十字的思路,没压缩复杂度,硬搞了 O ( n 3 ) O(n^3) O(n3)的循环

#include <bits/stdc++.h>
using namespace std;
typedef long double ld;

int n, m;
ld ans;
ld pi = acos(-1);

int main()
{
	scanf("%d%d", &n, &m);
	ans = 0;
	for (int k = 1; k <= m; ++k)
	{
		ld dis = min((ld)2.0, pi / m * k);
		ld delta;
		for (int i = 1; i <= n; ++i)
		{
			for (int j = i; j <= n; ++j)
			{
				if (k == m)
					delta = 2 * j;
				else
					delta = (dis * i + (j - i)) * 2;
				if (j != i)
					delta *= 2;
				delta *= 2 * m;
				ans += delta;
			}
		}
	}
	if (m != 1)
	{
		for (int i = 1; i <= n; ++i)
			ans += (ld)4 * m * i;
	}
	printf("%.10Lf\n", ans / 2);
	return 0;
}

济南站

L题也是数位DP,这个比较难顶,需要稍微分类讨论一下下
但是状态比较复杂,需要枚举后七位的可能值,并且讨论是否存在进位的情况。

根据题解,发现只需要枚举第七位以上连续1的奇偶性,7位以上所有数字的奇偶性即可
且枚举7以下位数的过程可以作为边界条件单独计算,可以略去这一维度

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int m, t, n;
const int maxn = 105, maxb = 64;
ll L;
int l[maxb], a[maxn];
ll rslt[2][2][2];
ll dp[maxb][2][2][2];
// [pos][sum][0~6][even]

ll calc(int lim, int s, int t)
{
	ll ans = 0, x = lim ? L % 128 : 127;
	for (int j = 0; j <= x; ++j)
	{
		bool flag = 1;
		for (int i = 0; i < m; ++i)
		{
			bool tmp = __builtin_parity(i + j) ^ s;
			if (i + j >= 128)
				tmp ^= t;
			if (tmp != a[i])
			{
				flag = 0;
				break;
			}
		}
		if (flag)
			ans++;
	}
	return ans;
}

ll dfs(int pos, int lim, int s, int t)
{
	ll &d = dp[pos][lim][s][t];
	if (d != -1)
		return d;
	if (pos < 7)
	{
		d = rslt[lim][s][t];
		return d;
	}
	d = 0;
	int I = lim ? l[pos] : 1;
	for (int i = 0; i <= I; ++i)
		d += dfs(pos - 1, lim & (i == I), s ^ i, i & (!t));
	return d;
}

ll solve()
{
	memset(dp, -1, sizeof(dp));
	n = -1;
	for (ll tmpl = L; tmpl; tmpl >>= 1)
		l[++n] = tmpl & 1;
	for (int i = 0; i < 8; ++i)
		rslt[i & 1][(i >> 1) & 1][(i >> 2) & 1] = calc(i & 1, (i >> 1) & 1, (i >> 2) & 1);
	return dfs(n, 1, 0, 0);
}

int main()
{
	// freopen("lin", "r", stdin);
	scanf("%d", &t);
	for (int tmp; t--;)
	{
		scanf("%d%lld", &m, &L);
		for (int i = 0; i < m; ++i)
			scanf("%d", &a[i]);
		printf("%lld\n", solve());
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值