起床困难综合征,随便构造一下就好了。
#include
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
int n, x, y = 1023;
char opt[3];
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
n = Read();
for (int i = 1, z; i <= n; i ++)
{
scanf("%s", opt), z = Read();
if (opt[0] == '&')
x &= z, y &= z;
else if (opt[0] == '|')
x |= z, y |= z;
else
x ^= z, y ^= z;
}
puts("2");
printf("& %d\n", x ^ y);
printf("^ %d\n", x);
return 0;
}
先用栈把内部的消掉,剩下的一定是消一头一尾。
消的时候如果一头一尾的出现次数加起来恰好为 k 就消下去,注意一些边界情况。
#include
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 100005;
int n, m, q, c, a[MAXN], b[MAXN];
LL ans;
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
n = Read(), m = Read(), q = Read();
for (int i = 1, x; i <= n; i ++)
if ((x = Read()) == a[c])
{
b[c] ++;
if (b[c] == m)
c --;
}
else
c ++, a[c] = x, b[c] = 1;
if (!c)
return puts("0"), 0;
int tot = 0, del = 0, pos = 0;
for (int i = 1; i <= c; i ++)
tot += b[i];
for (int i = 1; i < c + 1 - i; i ++)
if (a[i] == a[c + 1 - i] && b[i] + b[c + 1 - i] == m)
del += m;
else
{
pos = i;
break;
}
if (pos)
{
if (a[pos] == a[c + 1 - pos] && b[pos] + b[c + 1 - pos] > m)
del += m;
ans = 1LL * tot * q - 1LL * del * (q - 1);
}
else
{
ans = 1LL * b[(c >> 1) + 1] * q % m;
if (ans)
ans += tot - b[(c >> 1) + 1];
}
cout << ans << endl;
return 0;
}
题目名字提示类似竞赛图。
首先变成图论问题, i 能赢 j 连边 (i,j) ,可以赢的人一定能到达所有点。
两个点之间至少有一条边,就是说缩环之后是一条链。
新加一个点可能带来缩掉若干个SCC,对于每个SCC维护每种属性的最大最小值,用set维护一下链上的相对位置关系,暴力缩环即可。
#include
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 50005;
int n, m, siz[MAXN], l[MAXN][10], r[MAXN][10];
set s;
inline bool Win(int x, int y)
{
for (int i = 0; i < m; i ++)
if (r[x][i] > l[y][i])
return true;
return false;
}
inline void Insert(int x)
{
siz[x] = 1;
while (true)
{
auto it = s.lower_bound(mp(l[x][0], x));
if (it != s.end() && Win(x, it -> yy))
{
for (int i = 0; i < m; i ++)
l[x][i] = min(l[x][i], l[it -> yy][i]), r[x][i] = max(r[x][i], r[it -> yy][i]);
siz[x] += siz[it -> yy];
s.erase(it);
}
else
break;
}
while (true)
{
auto it = s.lower_bound(mp(l[x][0], x));
if (it != s.begin())
{
it --;
if (Win(it -> yy, x))
{
for (int i = 0; i < m; i ++)
l[x][i] = min(l[x][i], l[it -> yy][i]), r[x][i] = max(r[x][i], r[it -> yy][i]);
siz[x] += siz[it -> yy];
s.erase(it);
}
else
break;
}
else
break;
}
s.insert(mp(l[x][0], x));
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
n = Read(), m = Read();
for (int i = 1; i <= n; i ++)
for (int j = 0; j < m; j ++)
l[i][j] = r[i][j] = Read();
for (int i = 1; i <= n; i ++)
Insert(i), printf("%d\n", siz[(-- s.end()) -> yy]);
return 0;
}
考虑将 ai 变成 0/1 ,那么取 max 和 min 相当于 or 和 and 操作。
每个序列可以用一个 2k 位二进制数表示,第 S 位表示初始的 0/1 状态为 S ,那么这个序列的状态是什么,用bitset加速即可。
#include
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 100005;
const int MAXM = 4100;
int n, m, q, c, a[12][MAXN];
bitset b[MAXN];
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
m = Read(), n = c = Read(), q = Read();
for (int i = 0; i < n; i ++)
for (int j = 0; j < m; j ++)
a[i][j] = Read();
for (int i = 0; i < n; i ++)
for (int j = 0; j < 1 << n; j ++)
if (j >> i & 1)
b[i][j] = 1;
for (int i = 1, opt, x, y; i <= q; i ++)
if ((opt = Read()) == 1)
x = Read() - 1, y = Read() - 1, b[n ++] = b[x] | b[y];
else if (opt == 2)
x = Read() - 1, y = Read() - 1, b[n ++] = b[x] & b[y];
else
{
x = Read() - 1, y = Read() - 1;
int ans = 0;
for (int j = 0; j < c; j ++)
{
int cur = 0;
for (int k = 0; k < c; k ++)
if (a[k][y] >= a[j][y])
cur |= 1 << k;
if (b[x][cur])
ans = max(ans, a[j][y]);
}
printf("%d\n", ans);
}
return 0;
}
首先单次询问可以倒着贪心做,如果是负数就把它乘二加到答案(最后合并),否则去和前一个合并。
求出 i 往前这样做一步的长度,倍增加速询问。
注意代码里虽然写了 2 层for,但是均摊下来应该是 nlogn 的。
#include
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 100005;
const int mod = 1e9 + 7;
int n, m, a[MAXN], bin[MAXN], inv[MAXN], s[MAXN], f[18][MAXN], g[18][MAXN];
inline int Get(int l, int r)
{
return 1LL * (s[r] - s[l - 1] + mod) * inv[l - 1] % mod;
}
inline int Solve(int l, int r)
{
int ret = 0;
for (int i = 17; ~i; i --)
if (f[i][r] >= l)
ret = (ret + g[i][r]) % mod, r = f[i][r];
ret = (ret + Get(l, r)) % mod;
return ret;
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
n = Read(), m = Read(), bin[0] = inv[0] = 1;
for (int i = 1; i <= n; i ++)
a[i] = Read(), bin[i] = (bin[i - 1] << 1) % mod, inv[i] = 1LL * inv[i - 1] * (mod + 1 >> 1) % mod, s[i] = (1LL * bin[i] * (a[i] + mod) + s[i - 1]) % mod;
for (int i = 1; i <= n; i ++)
{
LL cur = 0;
for (int j = i; j; j --)
{
cur = 2 * (cur + a[j]);
if (cur <= 0)
{
f[0][i] = j - 1, g[0][i] = (cur % mod + mod) % mod;
break;
}
else if (cur > 2000000000)
{
f[0][i] = -1;
break;
}
}
}
for (int i = 1; i < 18; i ++)
for (int j = 1; j <= n; j ++)
if (!~f[i - 1][j])
f[i][j] = -1;
else
f[i][j] = f[i - 1][f[i - 1][j]], g[i][j] = (g[i - 1][j] + g[i - 1][f[i - 1][j]]) % mod;
while (m --)
{
int l = Read(), r = Read(), ret = (a[l] + Solve(l + 1, r)) % mod;
printf("%d\n", (ret + mod) % mod);
}
return 0;
}
质量挺高的…感觉姿势不对这场每个题(除了A)细节都会比较鬼畜…