Luogu7740 [NOI2021]机器人游戏 做题记录
link 一道炸裂的题目。
首先样例解释已经告诉我们可以容斥。考虑枚举可行的位置集合
显然每个机器人独立,可以分开考虑。对于一个机器人,他的行动对纸条的每个格子要么赋值为
对于一个机器人和一个格子
若一个格子同时存在状态
当
舍弃掉步数
考虑枚举最后一个处于
综上时间复杂度为
唯一能优化的地方在于
这样一来时间复杂度为
点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define pir pair <ll, ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
const ll maxn = 1010, mod = 1e9 + 7;
ll n, m, state[maxn][35], d[maxn], maxd, hh[1 << 16];
char str[maxn];
ll fas(ll x) {
if((x & 3) == 3) return 1;
if((x & 12) == 12) return 1;
if((x & -x) == x) return 3;
return 2;
}
ll _0[1 << 16], _1[1 << 16], _2[1 << 16], _3[1 << 16];
ll p0[1 << 16], p1[1 << 16], p2[1 << 16], p3[1 << 16];
void calc(ll q) {
for(ll i = 0; i < 16; i++) {
_0[1 << i] = p0[q] << i;
_1[1 << i] = p1[q] << i;
_2[1 << i] = (p2[q] << i) | ((1 << i) - 1);
_3[1 << i] = p3[q] << i;
}
for(ll S = 1; S < (1 << 16); S++) {
_0[S] = _0[S & (S - 1)] | _0[S & -S];
_1[S] = _1[S & (S - 1)] | _1[S & -S];
_2[S] = _2[S & (S - 1)] | _2[S & -S];
_3[S] = _3[S & (S - 1)] | _3[S & -S];
}
}
ll g(ll S, ll i) {
return (((_3[S] >> i) & 1) << 3) | (((_2[S] >> i) & 1) << 2)
| (((_1[S] >> i) & 1) << 1) | ((_0[S] >> i) & 1);
}
ll pw3[maxn], pw2[maxn];
namespace sub1 {
ll prod[1 << 16], pf[1 << 16], id[maxn];
ll solve() {
ll ret = 0;
for(ll S = 1; S < (1 << 16); S++) prod[S] = pf[S] = 1;
for(ll i = 1; i <= m; i++) {
calc(i); ll w = min(16ll, n - d[i]);
for(ll S = 1; S < (1 << w); S++) {
ll mask = (_0[S] & _1[S]) | (_2[S] & _3[S]);
ll cc = (((1ll << n) - 1) ^ (_0[S] | _1[S])) |
(((1ll << n) - 1) ^ (_2[S] | _3[S]));
cc &= ((1ll << n) - 1) ^ mask;
ll x = __builtin_popcountll(cc), z = __builtin_popcountll(mask);
ll tmp = pw3[x] * pw2[n - x - z] %mod;
prod[S] = prod[S] * tmp %mod;
if(d[i] < 16) pf[S] = pf[S] * tmp %mod;
}
}
for(ll S = 1; S < (1 << 16); S++) {
ll c = mod - 1;
for(ll i = 0; i < 16; i++)
if(S & (1 << i)) c = mod - c;
ret = (ret + c * (prod[S] + mod - pf[S])) %mod;
} return ret;
}
}
namespace sub2 {
ll dp[2][1 << 16][2], prod[1 << 16], prod_[1 << 16], rev[1 << 16];
ll id[maxn];
bool cmp(ll x, ll y) {return d[x] < d[y];}
ll solve() {
for(ll i = 1; i <= m; i++) id[i] = i;
sort(id + 1, id + 1 + m, cmp);
ll maxd = 0;
for(ll i = 1; i <= m; i++)
if(d[i] < 16) maxd = max(maxd, d[i] + 1);
if(maxd == 0) return 1;
for(ll S = 0; S < (1 << 16); S++) {
prod[S] = prod_[S] = 1;
rev[S] = (rev[S >> 1] >> 1) | (S & 1? 1 << maxd - 1 : 0);
} ll ret = 0;
for(ll t = n - 1, r = 0; ~t; t--) {
while(r < m && d[id[r + 1]] + t < n) {
++r; if(d[id[r]] >= 16) continue;
calc(id[r]);
for(ll S = 0; S < (1 << maxd); S++) {
ll x = hh[S & -S];
prod[rev[S]] = prod[rev[S]] * fas(g(S, maxd - 1)) %mod;
prod_[rev[S]] = prod_[rev[S]] * fas(g(S, maxd - 1) | 4) %mod;
}
}
memset(dp[1], 0, sizeof dp[1]);
dp[1][0][0] = mod - 1;
for(ll i = 0; i < n; i++) {
memset(dp[i & 1], 0, sizeof dp[i & 1]);
for(ll S = 0; S < (1 << maxd - 1); S++) {
for(ll z = 0; z < 2; z++) {
ll T = S ^ (S & (maxd > 1? 1 << maxd - 2 : 0)), e = (S > T) | z;
if(i ^ t)
dp[i & 1][T << 1][e] = (dp[i & 1][T << 1][e] + dp[i & 1 ^ 1][S][z] *
(i < t || z? prod_[S << 1] : prod[S << 1])) %mod;
if(i > t) continue;
ll of = maxd > 1? T << 1|1 : 0;
if(maxd == 1) e = 1;
dp[i & 1][of][e] = (dp[i & 1][of][e] + mod - dp[i & 1 ^ 1][S][z] *
(i < t || z? prod_[S << 1|1] : prod[S << 1|1]) %mod) %mod;
}
}
// for(ll S = 0; S < (1 << maxd - 1); S++)
// printf("dp[%lld, %lld] = %lld, %lld\n", i, S, dp[i & 1][S][0], dp[i & 1][S][1]);
}
for(ll S = 0; S < (1 << maxd - 1); S++)
ret = (ret + dp[n & 1 ^ 1][S][0] + dp[n & 1 ^ 1][S][1]) %mod;
}
return ret;
}
}
int main() {
scanf("%lld%lld", &n, &m);
pw2[0] = pw3[0] = 1;
for(ll i = 1; i <= n; i++) {
pw2[i] = pw2[i - 1] * 2 %mod;
pw3[i] = pw3[i - 1] * 3 %mod;
}
for(ll i = 0; i < 16; i++) hh[1 << i] = i;
for(ll i = 1; i <= m; i++) {
scanf("%s", str + 1); ll len = strlen(str + 1);
for(ll j = 0; j < n; j++) state[i][j] = 2;
for(ll j = 1, x = 0; j <= len; j++) {
if(str[j] == 'R') ++x;
else if(str[j] == '*') state[i][x] ^= 1;
else state[i][x] = str[j] - '0';
d[i] = x;
} maxd = max(maxd, d[i]);
for(ll j = d[i] + 1; j < n; j++) state[i][j] = 2;
for(ll j = 0; j < n; j++)
if(state[i][j] == 0) p0[i] |= 1ll << j;
else if(state[i][j] == 1) p1[i] |= 1ll << j;
else if(state[i][j] == 2) p2[i] |= 1ll << j;
else p3[i] |= 1ll << j;
} ll ans = 0;
ans += sub1::solve();
ans += sub2::solve();
printf("%lld", ans % mod);
return 0;
}
出处:https://www.cnblogs.com/Sktn0089/p/18337659
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现