2019 Multi-University Training Contest 1
Blank
题目要求只能放四个数,并且对于每个区间而言,统计个数时会发现只有最后一个位置有贡献,所以考虑(dp(i,j,k,t,p))表示前(i)个字符,四个数的最后一个位置从小到大为(j,k,t,p),之后就对于每个在(i)结束的区间,检验状态的合法性就行了。
这里有两个优化,一个就是(i)肯定会和后面的四个之一相等,那么就可以减掉一维;另一个就是还可以考虑一下滚动数组。
细节见代码吧:
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 105, MOD = 998244353;
int T, n, m;
int dp[2][N][N][N];
struct Seg{
int l, r, x;
}s[N];
int add(int &x, int y) {
return (x += y) >= MOD ? x - MOD : x;
}
vector <int> v[N];
int cnt[5];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> T;
while(T--) {
cin >> n >> m;
memset(dp, 0, sizeof(dp));
dp[0][0][0][0] = 1;
for(int i = 1; i <= n; i++) v[i].clear();
for(int i = 1; i <= m; i++) {
cin >> s[i].l >> s[i].r >> s[i].x;
v[s[i].r].push_back(i);
}
int cur = 0;
for(int d = 0; d < n; d++) {
for(int a = 0; a <= d; a++) {
for(int b = a; b <= d; b++) {
for(int c = b; c <= d; c++) {
dp[cur ^ 1][a][b][d] = add(dp[cur ^ 1][a][b][d], dp[cur][a][b][c]);
dp[cur ^ 1][a][c][d] = add(dp[cur ^ 1][a][c][d], dp[cur][a][b][c]);
dp[cur ^ 1][b][c][d] = add(dp[cur ^ 1][b][c][d], dp[cur][a][b][c]);
dp[cur ^ 1][a][b][c] = add(dp[cur ^ 1][a][b][c], dp[cur][a][b][c]);
}
}
}
for(int a = 0; a <= d; a++) for(int b = a; b <= d; b++) for(int c = b; c <= d; c++) {
dp[cur][a][b][c] = 0;
for(auto i : v[d + 1]) {
if(1 + (a >= s[i].l) + (b >= s[i].l) + (d >= s[i].l) != s[i].x) dp[cur ^ 1][a][b][d] = 0;
if(1 + (a >= s[i].l) + (c >= s[i].l) + (d >= s[i].l) != s[i].x) dp[cur ^ 1][a][c][d] = 0;
if(1 + (b >= s[i].l) + (c >= s[i].l) + (d >= s[i].l) != s[i].x) dp[cur ^ 1][b][c][d] = 0;
if(1 + (a >= s[i].l) + (b >= s[i].l) + (c >= s[i].l) != s[i].x) dp[cur ^ 1][a][b][c] = 0;
}
}
cur ^= 1;
}
int ans = 0;
for(int a = 0; a <= n; a++) {
for(int b = a; b <= n; b++) {
for(int c = b; c <= n; c++) {
ans = add(ans, dp[cur][a][b][c]);
}
}
}
cout << ans << '
';
}
return 0;
}
Operation
这个题要求强制在线,所以思考怎么快速求出区间的线性基来搞,因为求区间异或最大值一般而言都会求出区间的线性基。
显然暴力是不行的,但是通过一些可持久算法我们能得到一些启发,就是维护一个前缀线性基,注意维护线性基时注意贪心选基的位置,即每个基尽量选在右边的。
详见代码:
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int T, n, m;
int v[N][32], pos[N][32];
void insert(int p, int val) {
for(int i = 0; i <= 31; i++) v[p][i] = v[p - 1][i], pos[p][i] = pos[p - 1][i];
int k = p;
for(int i = 31; i >= 0; i--) {
if(val >> i & 1) {
if(!v[p][i]) {
v[p][i] = val;
pos[p][i] = k;
return;
}
if(pos[p][i] < k) {
swap(k, pos[p][i]);swap(val, v[p][i]);
}
val ^= v[p][i];
}
}
}
int query(int l, int r) {
int ans = 0;
for(int i = 31; i >= 0; i--) {
if(pos[r][i] >= l && (ans ^ v[r][i]) > ans) ans ^= v[r][i];
}
return ans;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> T;
while(T--) {
cin >> n >> m;
for(int i = 1, x; i <= n; i++) {
cin >> x; insert(i, x);
}
int ans = 0;
while(m--) {
int op; cin >> op;
if(op) {
int x; cin >> x; x ^= ans;
insert(++n, x);
} else {
int l, r; cin >> l >> r;
l = (l ^ ans) % n + 1, r = (r ^ ans) % n + 1;
if(l > r) swap(l, r);
cout << (ans = query(l, r)) << '
';
}
}
}
return 0;
}
Vacation
做法有点多:单调队列模拟、二分时间等等。
但这里有个线性的做法,我们会发现最后一定是一堆车在一起通过终点的,我们就枚举最后有多少个车在一起通过终点,然后计算时间,取(max)即可。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n;
int l[N], s[N], v[N];
int main() {
while(scanf("%d", &n) != EOF) {
for(int i = 0; i <= n; i++) scanf("%d", &l[i]);
for(int i = 0; i <= n; i++) scanf("%d", &s[i]);
for(int i = 0; i <= n; i++) scanf("%d", &v[i]);
ll sum = 0;
double ans = (double)s[0] / v[0];
for(int i = 1; i <= n; i++) {
ans = max(ans, (double)((sum += l[i]) + s[i]) / v[i]);
}
printf("%.10f
", ans);
}
return 0;
}
Path
求出最短路图,然后求最小割即可。
代码如下:
Code
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
#define t n
using namespace std;
typedef long long ll;
const int N = 1e4 + 5;
int T, n, m;
struct Edge{
int v, w, next;
}e[N << 1];
struct edge{
int u, v, w;
}E[N];
struct node{
ll d;
int u;
bool operator < (const node &A)const {
return d > A.d;
}
};
bool vis[N];
int head[N], tot;
void adde(int u, int v, int w) {
e[tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++;
}
ll d[N], d2[N];
void Dij(int x) {
priority_queue <node> q;
memset(vis, 0, sizeof(vis));
memset(d, INF, sizeof(d)) ;d[x] = 0;
q.push(node{0, x});
while(!q.empty()) {
node now = q.top(); q.pop();
int u = now.u;
if(vis[u]) continue ;
vis[u] = 1;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(d[v] > now.d + e[i].w) {
d[v] = now.d + e[i].w;
q.push(node{d[v], v});
}
}
}
}
void Dij2(int x) {
priority_queue <node> q;
memset(vis, 0, sizeof(vis));
memset(d2, INF, sizeof(d2)) ;d2[x] = 0;
q.push(node{0, x});
while(!q.empty()) {
node now = q.top(); q.pop();
int u = now.u;
if(vis[u]) continue ;
vis[u] = 1;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(d2[v] > now.d + e[i].w) {
d2[v] = now.d + e[i].w;
q.push(node{d2[v], v});
}
}
}
}
void adde2(int u, int v, int w) {
e[tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++;
e[tot].v = u; e[tot].w = 0; e[tot].next = head[v]; head[v] = tot++;
}
bool bfs(int S,int T){
memset(d,0,sizeof(d));d[S]=1;
queue <int > q;q.push(S);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(!d[v] && e[i].w>0){
d[v]=d[u]+1;
q.push(v);
}
}
}
return d[T]!=0;
}
ll dfs(int S,int a){
ll flow=0,f;
if(S==t || a==0) return a;
for(int i=head[S];i!=-1;i=e[i].next){
int v=e[i].v;
if(d[v]!=d[S]+1) continue ;
f=dfs(v,min(a,e[i].w));
if(f){
e[i].w-=f;
e[i^1].w+=f;
flow+=f;
a-=f;
if(a==0) break;
}
}
if(!flow) d[S]=-1;
return flow;
}
int Dinic(){
int max_flow=0;
while(bfs(1,t)) max_flow+=dfs(1,INF);
return max_flow;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> T;
while(T--) {
memset(head, -1, sizeof(head)); tot = 0;
cin >> n >> m;
for(int i = 1; i <= m; i++) {
int x, y, c; cin >> x >> y >> c;
E[i] = {x, y, c};
adde(y, x, c);
}
Dij(n);
if(d[1] == INF) {
cout << 0 << '
';
continue ;
}
memset(head, -1, sizeof(head)); tot = 0;
for(int i = 1; i <= m; i++) adde(E[i].u, E[i].v, E[i].w);
Dij2(1);
memset(head, -1, sizeof(head)); tot = 0;
for(int i = 1; i <= m; i++) {
int u = E[i].u, v = E[i].v;
if(d2[u] + d[v] + E[i].w == d[1]) {
adde2(u, v, E[i].w);
}
}
cout << Dinic() << '
';
}
return 0;
}
String
贪心构造即可,然后每次贪心选择后,check一下剩下的可不可以满足条件。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5, MAX = 26;
char s[N];
int n, k;
int L[MAX], R[MAX], used[MAX], cnt[MAX];
int suf[N][MAX];
vector <char> ans;
vector <int> v[MAX];
bool ok(int x, int p) {
int sum1 = 0, sum2 = 0;
for(int i = 0; i < MAX; i++) {
int pl = max(L[i] - used[i], 0), pr = min(R[i] - used[i], suf[n][i] - suf[p][i]);
if(pr < pl) return false;
sum1 += pl; sum2 += pr;
}
return sum1 <= x && x <= sum2;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
while(cin >> s + 1 >> k) {
n = strlen(s + 1);
for(int i = 0; i < MAX; i++) v[i].clear(), cnt[i] = used[i] = 0; ans.clear();
for(int i = 1; i <= n; i++) v[s[i] - 'a'].push_back(i), cnt[s[i] - 'a']++;
for(int i = 1; i <= n; i++) {
for(int j = 0; j < MAX; j++) suf[i][j] = suf[i - 1][j];
suf[i][s[i] - 'a']++;
}
for(int i = 0; i < MAX; i++) cin >> L[i] >> R[i];
int last = 0, f = 1;
for(int i = 1; i <= k && f; i++) {
for(int j = 0; j < MAX; j++) {
int pos = lower_bound(v[j].begin(), v[j].end(), last + 1) - v[j].begin();
int SZ = (int)v[j].size();
used[j]++;
if(SZ == pos || !ok(k - i, v[j][pos])) {
used[j]--;
if(j == MAX - 1) {
cout << -1; f = 0; break;
}
continue ;
}
last = v[j][pos]; cnt[j]--;
ans.push_back(j + 'a');
break;
}
}
for(auto t : ans) cout << t;
cout << '
';
}
return 0;
}
Function
化简式子即可,感觉题解还是挺清楚的了。。(其实是我懒得再照着打一次了= =)
注意一下上界吧,感觉数论题细节还是挺多的。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e7 + 5, MOD = 998244353;
template <class T>
void read(T &x) {
static char ch; static bool neg;
for(ch = neg = 0; ch < '0' || ch > '9'; neg |= (ch == '-'), ch = getchar());
for(x = 0; ch >= '0' && ch <= '9'; x = x * 10 + ch - '0', ch = getchar());
x = neg ? -x : x;
}
int Add(int x, int const &y) {
return (x += y) >= MOD ? x - MOD : x;
}
int Mul(long long x, int const &y) {
return x * y % MOD;
}
int v[N], prime[N], phi[N], tot;
void pre() {
phi[1] = 1;
for(int i = 2; i <= N - 1; i++) {
if(!v[i]) {
v[i] = i;
prime[++tot] = i, phi[i] = i - 1;
}
for(int j = 1; j <= tot; j++) {
if(prime[j] > v[i] || prime[j] > (N - 1) / i) break ;
v[i * prime[j]] = prime[j];
phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
}
}
}
__int128 n;
int T;
int calc(int k, __int128 L, __int128 R) {
int ans = 0;
for(int i = 1; 1ll * i * i <= k; i++) {
if(k % i == 0) {
ans = Add(ans, Mul((R / i - L / i) % MOD, phi[i]));
if(k / i != i)
ans = Add(ans, Mul((R / (k / i) - L / (k / i)) % MOD, phi[k / i]));
}
}
return ans;
}
int Sum1(long long x) {
return x * (x + 1) / 2 % MOD;
}
int Sum2(long long x) {
return x * (x + 1) % (6LL * MOD) * (2 * x + 1) / 6 % MOD;
}
int main() {
pre();
read(T);
while(T--) {
read(n);
if(n <= 7) {
printf("%d
", (int)n);
continue ;
}
int r;
for(r = 1; (__int128)(r + 2) * (r + 2) * (r + 2) - 1 <= n; r++);
int ans = calc(r + 1, (__int128)(r + 1) * (r + 1) * (r + 1) - 1, n);
for(int i = 1; i <= r; i++) {
ans = Add(ans, Mul(Add(Add(Mul(3ll * i, Sum2(r / i)), 3ll * Sum1(r / i) % MOD), r / i), phi[i]));
}
printf("%d
", ans);
}
return 0;
}