吐槽一下最近讲课太累了都没啥时间补题了,哎,队友也不补题
f i , j , k , l f_{i,j,k,l} fi,j,k,l表示四种颜色的最后的位置排序之后的结果,然后滚动掉最后一维就好了
/* ***********************************************
Author :BPM136
Created Time :7/24/2019 8:07:39 PM
File Name :1001.cpp
************************************************ */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int const N = 105;
int const mod = 998244353;
inline void update(int& a, int b) {
a += b;
if (a >= mod)
a -= mod;
}
vector<pii> t[N];
int f[N][N][N][2];
int main() {
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
for (int i = 0; i <= n; ++i) {
t[i].clear();
t[i].emplace_back(i, 1);
}
for (int i = 0; i < m; ++i) {
int x, y, c;
cin >> x >> y >> c;
t[y].emplace_back(x, c);
}
memset(f, 0, sizeof(f));
f[0][0][0][0] = 1;
for (int p = 1; p <= n; ++p) {
int now = p & 1;
for (int i = 0; i <= p; ++i)
for (int j = i; j <= p; ++j)
for (int k = j; k <= p; ++k)
f[i][j][k][now] = 0;
for (int i = 0; i <= p; ++i)
for (int j = i; j <= p; ++j)
for (int k = j; k <= p; ++k) {
update(f[j][k][p - 1][now], f[i][j][k][now ^ 1]);
update(f[i][k][p - 1][now], f[i][j][k][now ^ 1]);
update(f[i][j][p - 1][now], f[i][j][k][now ^ 1]);
update(f[i][j][k][now], f[i][j][k][now ^ 1]);
}
for (int i = 0; i <= p; ++i)
for (int j = i; j <= p; ++j)
for (int k = j; k <= p; ++k)
for (auto const& lim : t[p]) {
auto l = lim.first, sum = lim.second;
auto s = (i >= l) + (j >= l) + (k >= l) + 1;
if (s != sum)
f[i][j][k][now] = 0;
}
}
int ans = 0;
for (int i = 0; i <= n; ++i)
for (int j = i; j <= n; ++j)
for (int k = j; k <= n; ++k)
update(ans, f[i][j][k][n & 1]);
cout << ans << '\n';
}
return 0;
}
优秀的线性基,因为一个位置的前缀的线性基最多只有本质K种而已,然后就维护一下线性基每个位置最后的数的位置就好了。
/* ***********************************************
Author :BPM136
Created Time :7/24/2019 9:21:12 PM
File Name :1002.cpp
************************************************ */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
int const N = 1000005;
int f[N][32], pos[N][32];
int n, m;
void add(int k, int val) {
for (int i = 30; i >= 0; --i) {
f[k][i] = f[k - 1][i];
pos[k][i] = pos[k - 1][i];
}
int now = k;
for (int i = 30; i >= 0; --i)
if (val & (1 << i)) {
if (f[now][i] == 0) {
f[now][i] = val;
pos[now][i] = k;
return;
} else {
if (k > pos[now][i]) {
swap(pos[now][i], k);
swap(f[now][i], val);
}
val ^= f[now][i];
}
}
}
int getAns(int l, int r) {
int ret = 0;
for (int i = 30; i >= 0; --i)
if (pos[r][i] >= l && (ret ^ f[r][i]) > ret)
ret ^= f[r][i];
return ret;
}
int main() {
USE_CIN_COUT;
int T;
cin >> T;
while (T--) {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
int x;
cin >> x;
add(i, x);
}
int lastans = 0;
while (m--) {
int op;
cin >> op;
if (op == 0) {
int l, r;
cin >> l >> r;
l = (l ^ lastans) % n + 1;
r = (r ^ lastans) % n + 1;
if (l > r)
swap(l, r);
cout << (lastans = getAns(l, r)) << '\n';
} else {
int x;
cin >> x;
x ^= lastans;
add(++n, x);
}
}
}
return 0;
}
写了个并查集每次往前合并,然后set暴力修改碰撞时间的东西,然而可以二分答案,还可以线性求答案(因为一定是某车卡住了最后一辆,然后就可以求出如果这辆车是卡住的那个,那么时间是多少,最后取个max就行)
/* ***********************************************
Author :BPM136
Created Time :7/22/2019 3:55:25 PM
File Name :1004.cpp
************************************************ */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef long double db;
typedef unsigned int ui;
typedef unsigned long long ull;
int const N = 200005;
db const inf = 1e30;
int len[N], s[N], v[N];
int uns[N], unslen[N], unsmin[N];
db unss[N], unst[N];
db chu;
db tim[N];
int unsFind(int x) {
if (uns[x] == x)
return x;
return uns[x] = unsFind(uns[x]);
}
db calc(int x, int y) {
int dx = unsFind(x), dy = unsFind(y);
if (dx == dy)
return 0;
if (v[dx] > v[dy]) {
db dis = 1.0 * unss[dy] + v[dy] * unst[dy] + 1.0 * unslen[dy] - unss[dx] - v[dx] * unst[dx];
// cerr << "d : " << dis << ' ' << v[dy] - v[dx] << '\n';
return dis / (1.0 * (v[dy] - v[dx]));
}
return inf;
}
db ans = 0;
bool chk(db ti) {
int dx = unsFind(0);
if (1.0 * unss[dx] + unslen[dx] - chu <= v[dx] * (ti - unst[dx])) {
ans = 1.0 * unss[dx] + unslen[dx] - chu + v[dx] * unst[dx];
ans = ans / v[dx];
return 1;
}
return 0;
}
struct node {
db time;
int i;
bool operator < (node const& oth) const {
if (time == oth.time)
return i > oth.i;
return time < oth.time;
}
};
int main() {
USE_CIN_COUT;
int n;
while (cin >> n) {
for (int i = 0; i <= n; ++i)
cin >> len[i];
for (int i = 0; i <= n; ++i)
cin >> s[i];
for (int i = 0; i <= n; ++i)
cin >> v[i];
chu = len[0];
for (int i = 0; i <= n; ++i) {
uns[i] = i;
unslen[i] = len[i];
unsmin[i] = i;
unss[i] = s[i];
unst[i] = 0;
}
auto S = set<node>();
for (int i = 0; i < n; ++i) {
db t = calc(i, i + 1);
tim[i] = t;
S.insert(node{ t, i });
// cerr << t << ' ';
}
// cerr << '\n';
node infnode = node{ inf, 0 }, it;
for (; ; ) {
it = infnode;
if (SZ(S)) {
it = *S.begin();
S.erase(S.begin());
}
// cerr << it.time << ' ' << it.i << '\n';
if (chk(it.time)) {
cout << fixed << setprecision(10) << ans << '\n';
break;
}
auto pos = it.i;
auto dx = unsFind(pos), dy = unsFind(pos + 1);
uns[dx] = dy;
unslen[dy] += unslen[dx];
unsmin[dy] = unsmin[dx];
unss[dy] = unss[dy] - (it.time - unst[dy]) * v[uns[dy]];
unst[dy] = it.time;
int pre = unsmin[dy] - 1;
if (pre >= 0) {
double ti = calc(pre, dy);
auto iter = S.find(node{ tim[pre], pre });
if (iter != S.end())
S.erase(iter);
tim[pre] = ti;
S.insert(node{ tim[pre], pre });
}
}
}
return 0;
}
最短路DAG上最小流即可
/* ***********************************************
Author :BPM136
Created Time :7/22/2019 2:48:20 PM
File Name :1005.cpp
************************************************ */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef pair<ll, int> pli;
int const N = 10005;
int const M = 40005;
ll const inf = 1e15;
struct ISAP {
struct Edge {
int y,next;
ll f;
}e[M];
int last[N],ne;
int d[N],cur[N],pre[N],num[N];
int S,T,nv;
void init(int _n) {
S=_n+1; T=_n+2;
nv=T+1;
ne=0;
memset(last,-1,sizeof(last));
}
void add(int x,int y,ll f) {
e[ne].y=y; e[ne].f=f; e[ne].next=last[x]; last[x]=ne; ne++;
}
void link(int x,int y,ll f) {
add(x,y,f);
add(y,x,0);
}
void rev_bfs() {
memset(num,0,sizeof(num));
memset(d,-1,sizeof(d));
d[T]=0;
num[0]=1;
queue<int> Q;
while(!Q.empty()) Q.pop();
Q.push(T);
while(!Q.empty()) {
int x=Q.front(); Q.pop();
for(int i=last[x];~i;i=e[i].next) {
int y=e[i].y;
if(~d[y]) continue;
d[y]=d[x]+1;
num[d[y]]++;
Q.push(y);
}
}
}
ll solve() {
memset(pre,0,sizeof(pre));
memcpy(cur,last,sizeof(cur));
rev_bfs();
if(d[S]==-1) return 0; ///不联通
ll ret=0;
int u=pre[S]=S,i;
while(d[T]<nv) {
if(u==T) {
ll f=inf;
int neck = 0;
for(i=S;i!=T;i=e[cur[i]].y) {
if(f>e[cur[i]].f) {
f=e[cur[i]].f;
neck=i;
}
}
for(i=S;i!=T;i=e[cur[i]].y) {
e[cur[i]].f-=f;
e[cur[i]^1].f+=f;
}
ret+=f;
u=neck;
}
for(i=cur[u];~i;i=e[i].next) if(d[e[i].y]+1==d[u] && e[i].f) break;
if(~i) {
cur[u]=i;
pre[e[i].y]=u;
u=e[i].y;
} else {
if(0== (--num[d[u]])) break;
int mind=nv;
for(i=last[u];~i;i=e[i].next) {
if(e[i].f && mind>d[e[i].y]) {
cur[u]=i;
mind=d[e[i].y];
}
}
d[u]=mind+1;
num[d[u]]++;
u=pre[u];
}
}
return ret;
}
}isap;
struct edge {
int y, c;
int next;
}e[M << 1];
int last[N], ne;
int n, m;
void addedge(int x, int y, int c) {
e[++ne].y = y;
e[ne].c = c;
e[ne].next = last[x];
last[x] = ne;
}
void dijstra(int S, std::vector<ll>& dis) {
std::priority_queue<pli, std::vector<pli>, std::greater<pli>> Q;
dis.resize(n);
std::vector<bool> vis;
vis.resize(n);
for(int i = 0; i <= n; ++i)
dis[i] = inf, vis[i] = 0;
dis[S] = 0;
Q.push(std::make_pair(0ll, S));
while(Q.empty() == 0) {
pli now = Q.top();
Q.pop();
if(vis[now.second]) continue;
vis[now.second] = 1;
for(int i = last[now.second]; i != 0; i = e[i].next) {
if(dis[e[i].y] > dis[now.second] + e[i].c) {
dis[e[i].y] = dis[now.second] + e[i].c;
Q.push(std::make_pair(dis[e[i].y], e[i].y));
}
}
}
}
int main() {
USE_CIN_COUT;
int T;
cin >> T;
while (T--) {
cin >> n >> m;
isap.init(n);
for (int i = 1; i <= n; ++i)
last[i] = 0;
ne = 0;
for (int i = 1; i <= m; ++i) {
int x, y, c;
cin >> x >> y >> c;
addedge(x, y, c);
}
auto dis = vector<ll>(n + 1);
dijstra(1, dis);~~~
for (int i = 1; i <= n; ++i)
for (int j = last[i]; j; j = e[j].next)
if (dis[i] + e[j].c == dis[e[j].y])
isap.link(i, e[j].y, e[j].c);
isap.link(isap.S, 1, inf);
isap.link(n, isap.T, inf);
cout << isap.solve() << '\n';
}
return 0;
}
大力贪心即可,每次判断后面我们能不能同时满足限制即可
/* ***********************************************
Author :BPM136
Created Time :7/22/2019 7:23:30 PM
File Name :1009.cpp
************************************************ */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
int const N = 100005;
int l[27], r[27];
queue<int> tab[26];
int suf[N][26];
int now[26];
string s;
int n, m;
char ans[N];
bool chk(int p, int ch) {
int sum = 0, sum2 = 0;
// cerr << p << ' ' << ch << '\n';
for (int i = 0; i < 26; ++i) {
if (min(suf[p][i], n - m - 1) + now[i] + (ch == i) < l[i])
return 0;
sum += min(suf[p][i], r[i] - now[i] - (ch == i));
if (now[i] + (ch == i) < l[i])
sum2 += l[i] - now[i] - (ch == i);
}
// cerr << " ? " << sum << ' ' << sum2 << '\n';
if (sum < n - m - 1 || sum2 > n - m - 1)
return 0;
return 1;
}
int main() {
freopen("02", "r", stdin);
freopen("out.txt", "w", stdout);
while (cin >> s >> n) {
m = 0;
for (int i = 0; i < 26; ++i) {
cin >> l[i] >> r[i];
while (tab[i].empty() == 0)
tab[i].pop();
}
for (int i = 0; i < SZ(s); ++i)
tab[s[i] - 'a'].push(i);
fill(suf[SZ(s)], suf[SZ(s)] + 26, 0);
for (int i = SZ(s) - 1; i >= 0; --i) {
for (int j = 0; j < 26; ++j)
suf[i][j] = suf[i + 1][j];
suf[i][s[i] - 'a']++;
}
fill(now, now + 26, 0);
int p = -1;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < 26; ++j) {
while (tab[j].empty() == 0 && tab[j].front() <= p)
tab[j].pop();
if (tab[j].empty() || now[j] == r[j])
continue;
if (chk(tab[j].front(), j)) {
now[j]++;
ans[++m] = j + 'a';
p = tab[j].front();
// cerr << char(j + 'a') << ' ' << tab[j].front() << '\n';
break;
}
}
if (i != m)
break;
}
if (m < n)
cout << -1 << '\n';
else {
ans[++m] = '\0';
cout << ans + 1 << '\n';
}
}
return 0;
}
就是判断两个凸包是否有交即可(点在边上也算相交)