T1
狀壓 \(dp\),兩兩之間有相同的位,那一位就為 \(1\),否則就為 \(0\),考慮哪些選法不合法,要在 \(0\) 的位上為 \(1\),即只在 \(1\) 上選和不選都是不可以的,於是狀壓 \(dp\) 即可。
#include<iostream>
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
const int N = 3e3 + 10, M = 25;
int n, m, ans = 0x7fffffff;
char c[N][M];
bool flag[(1 << M)];
int sum[M];
void solve(){
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++){
int p = 0;
for (int k = 0; k < m; k++)
if (c[i][k] == c[j][k]) p |= (1 << k);
flag[p] = 1;
}
for (int i = (1 << m) - 1; i >= 0; i--){
if (flag[i])
for (int j = 0; j < m; j++)
if (i & (1 << j)) flag[i ^ (1 << j)] = 1;
int res = 0;
if (!flag[i]){
for (int j = 0; j < m; j++)
if (i & (1 << j)) res++;
if (res <= ans) ans = res, sum[ans]++;
}
}
cout << ans << ' ' << sum[ans] << '\n';
}
signed main(){
freopen("guess.in", "r", stdin);
freopen("guess.out", "w", stdout);
n = read(), m = read();
for (int i = 1; i <= n; i++) cin >> c[i];
solve();
return 0;
}
T2
找性質,發現一個連通塊,即包括有順序的 X
,Y
,D
,只會全部是豎的,要麼全部是橫的。
直接維護連通塊的橫與豎的權值即可。
#include<iostream>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
const int N = 3e3 + 10;
int n, ans;
char a[N][N];
int turn(int x, int y){
return (x - 1) * n + y;
}
int fa[N * N];
int find(int x){
return (x == fa[x] ? fa[x] : fa[x] = find(fa[x]));
}
int x[N * N], y[N * N];
void merge(int a, int b){
int fx = find(a), fy = find(b);
if (fx == fy) return;
fa[fy] = fx;
x[fx] += x[fy];
y[fx] += y[fy];
}
int main(){
freopen("match.in", "r", stdin);
freopen("match.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) cin >> a[i][j];
for (int i = 1; i <= n * n; i++) fa[i] = i;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
if (a[i][j] == 'X'){
if (a[i + 1][j] == 'Y' && a[i + 2][j] == 'D'){
merge(turn(i, j), turn(i + 1, j));
merge(turn(i, j), turn(i + 2, j));
y[find(turn(i, j))]++;
}
if (a[i][j + 1] == 'Y' && a[i][j + 2] == 'D'){
merge(turn(i, j), turn(i, j + 1));
merge(turn(i, j), turn(i, j + 2));
x[find(turn(i, j))]++;
}
}
}
}
for (int i = 1; i <= n * n; i++)
if (fa[i] == i) ans += max(x[i], y[i]);
cout << ans;
return 0;
}
T3
發現每個人要從時間最少的飲水機那裡接水才最優,每次將一個人加入接水時間的飲水機處,由於一個人加入後,這個飲水機的時間一定會比其它所有飲水機的等待時間長,那麼直接從 \(1\) 到 \(n\) 加入人,對於同樣時間的人線段樹最佳化貪心即可。
#include<iostream>
#include<algorithm>
#define ls now << 1
#define rs now << 1 | 1
#define int long long
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
const int N = 3e5 + 10, M = 1e6 + 10, mod = 1e9 + 7;
int n, m, ans;
struct node{
int a, t;
bool operator < (const node &b) const{
return t < b.t;
}
}p[N];
struct tree{
int sum, tag, l, r;
}t[M << 2];
void pushup(int now){
t[now].sum = (t[ls].sum + t[rs].sum) % mod;
}
void pushdown(int now){
int l = t[now].l, r = t[now].r, mid = (l + r) >> 1;
t[ls].sum = (t[ls].sum + t[now].tag * (mid - l + 1) % mod) % mod;
t[rs].sum = (t[rs].sum + t[now].tag * (r - mid) % mod) % mod;
t[ls].tag = (t[ls].tag + t[now].tag) % mod;
t[rs].tag = (t[rs].tag + t[now].tag) % mod;
t[now].tag = 0;
}
void build(int now, int l, int r){
t[now] = (tree){0, 0, l, r};
if (l == r) return;
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(now);
}
void modify(int now, int x, int y, int k){
int l = t[now].l, r = t[now].r;
if (x <= l && r <= y){
t[now].sum = (t[now].sum + (r - l + 1) * k % mod) % mod;
t[now].tag = (t[now].tag + k) % mod;
return;
}
pushdown(now);
int mid = (l + r) >> 1;
if (x <= mid) modify(ls, x, y, k);
if (mid + 1 <= y) modify(rs, x, y, k);
pushup(now);
}
int query(int now, int x, int y){
int l = t[now].l, r = t[now].r;
if (x <= l && r <= y){
return t[now].sum;
}
pushdown(now);
int mid = (l + r) >> 1, res = 0;
if (x <= mid) res = (res + query(ls, x, y)) % mod;
if (mid + 1 <= y) res = (res + query(rs, x, y)) % mod;
return res;
}
int work1(int &pos, int k, int t){
int l = min(m - pos + 1, k);
ans = (ans + query(1, pos, pos + l - 1)) % mod;
modify(1, pos, pos + l - 1, t % mod);
pos = ((pos + l) % m == 0 ? m : (pos + l) % m);
return l;
}
void work2(int turn, int t){
ans = (ans + query(1, 1, m) * turn % mod) % mod;
ans = (ans + ((turn - 1) * turn / 2) % mod * t % mod * m % mod) % mod;
modify(1, 1, m, turn * t % mod);
}
void work3(int &pos, int more, int t){
ans = (ans + query(1, 1, more)) % mod;
modify(1, 1, more, t % mod);
pos = more + 1;
}
signed main(){
freopen("water.in", "r", stdin);
freopen("water.out", "w", stdout);
n = read(), m = read();
for (int i = 1; i <= n; i++) p[i].a = read(), p[i].t = read();
sort(p + 1, p + n + 1);
build(1, 1, m);
int pos = 1;
for (int i = 1; i <= n; i++){
int k = p[i].a, t = p[i].t;
k -= work1(pos, k, t);
if (pos != 1) continue;
int turn = k / m, more = k % m;
if (turn) work2(turn, t);
if (more) work3(pos, more, t);
}
cout << ans;
return 0;
}
T4
不會。