ZOJ Monthly, January 2018
A 易知最优的方法是一次只拿一颗,石头数谁多谁赢,一样多后手赢
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 110; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; int main(){ int T = read(); while(T--){ N = read(); int ans = 0; for(int i = 1; i <= N; i ++) ans += read(); for(int i = 1; i <= N; i ++) ans -= read(); if(ans > 0) puts("BaoBao"); else puts("DreamGrid"); } return 0; }
B.
题意:给出N个字符串以及一系列查询,查询u,v两字符串的最大后缀可以成为所有字符串中多少字符串的前缀
由于N和Q以及字符串的长度是1e5级别的,暴力求出最大后缀然后匹配肯定不行。
考虑到在fail树中,每一个节点的父节点都是当前结点所代表字符串在所有字符串中的最长后缀。
所以u,v两字符串的最大公共后缀就是结点lca(u,v)代表的字符串
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 1e5 + 10; const int maxm = 5e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; char str[maxm]; int root,ttt; int nxt[maxm][26],fail[maxm],cnt[maxm]; int Index[maxn]; int newnode(){ for(int i = 0 ; i < 26; i ++) nxt[ttt][i] = -1; cnt[ttt] = 0; return ttt++; } void Init(){ ttt = 0; root = newnode(); } int insert(char *t){ int p = root; for(int i = 0; t[i]; i ++){ int id = t[i] - 'a'; if(nxt[p][id] == -1) nxt[p][id] = newnode(); p = nxt[p][id]; cnt[p]++; } return p; } struct Edge{ int to,next; }edge[maxm * 2]; int head[maxm],tot; void init(){ for(int i = 0 ; i <= ttt; i ++) head[i] = -1; tot = 0; } void add(int u,int v){ edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } void Build(){ queue<int>Q; for(int i = 0 ; i < 26; i ++){ if(nxt[root][i] == -1) nxt[root][i] = root; else{ fail[nxt[root][i]] = root; Q.push(nxt[root][i]); add(root,nxt[root][i]); } } while(!Q.empty()){ int u = Q.front(); Q.pop(); for(int i = 0 ; i < 26; i ++){ if(nxt[u][i] == -1) nxt[u][i] = nxt[fail[u]][i]; else{ fail[nxt[u][i]] = nxt[fail[u]][i]; add(nxt[fail[u]][i],nxt[u][i]); Q.push(nxt[u][i]); } } } } const int SP = 20; int pa[maxm][20],dep[maxm]; void dfs(int t){ for(int i = 1; i < SP; i ++) pa[t][i] = pa[pa[t][i - 1]][i - 1]; for(int i = head[t]; ~i ; i = edge[i].next){ int v = edge[i].to; pa[v][0] = t; dep[v] = dep[t] + 1; dfs(v); } } int lca(int u,int v){ if(dep[u] < dep[v]) swap(u,v); int t = dep[u] - dep[v]; for(int i = 0 ; i < SP; i ++) if(t & (1 << i)) u = pa[u][i]; for(int i = SP - 1; i >= 0; i --){ int uu = pa[u][i],vv = pa[v][i]; if(uu != vv){ u = uu; v = vv; } } return u == v ? u: pa[u][0]; } int main(){ while(~Sca(N)){ Init(); for(int i = 1; i <= N ; i ++){ scanf("%s",str); Index[i] = insert(str); } init(); Build(); pa[root][0] = root; dep[root] = 0; dfs(root); int Q = read(); while(Q--){ int u = Index[read()],v = Index[read()]; u = lca(u,v); if(!cnt[u]) puts("N"); else Pri(cnt[u]); } } return 0; }
D.
题意:给出N代表拥有1-N序列的椅子,给出10个数字,第i个数字ai表示有ai个人希望做i的倍数的椅子,问最多能安排多少符合条件的椅子。
首先考虑贪心,但10到1依次安排很容易可以证伪。
考虑最大流,起点给出ai个流量到i这个点表示i这个位置的人数,然后这些人分别通向他们可以满足的椅子,椅子再向终点连容量为1的边。
显然这样的方法时间和空间会炸穿。
考虑到很多椅子虽然序号不同但是其本质相同,例如都仅仅是1和3和9的倍数的9和81.
所以我们将所有的数归类成本质不同的数,预处理之后可发现种类只有48种。
接下来的问题在于1e9的椅子太多了,根本无法建图。可以考虑1-10的lcm为2520,也就是说2520为一个周期,我们预处理出一个周期的情况之后,就将N % 2520,将所有可以分成周期的部分累加,不可以分的部分最多为2519,直接单独计算即可。
这样就建出了S到10个点,分别流向48个点,48个点到T的图,跑最大流
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 1010; const int maxm = 1e6 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; int vis[1 << 11]; int num[61],Hash[3000]; PII road[1 << 11]; struct Edge{ int to,next,cap,flow; Edge(){} Edge(int to,int next,int cap,int flow):to(to),next(next),cap(cap),flow(flow){} }edge[maxm * 2]; int head[maxn],tot; void init(){ for(int i = 0 ; i <= 60 ;i ++) head[i] = -1; tot = 0; } inline void add(int u,int v,int w){ edge[tot] = Edge(v,head[u],w,0); head[u] = tot++; edge[tot] = Edge(u,head[v],0,0); head[v] = tot++; } int dep[maxn],pre[maxn]; inline bool BFS(int s,int t){ for(int i = 0 ; i <= 60; i ++) dep[i] = -1; queue<int>Q; Q.push(s); dep[s] = 0; while(!Q.empty()){ int u = Q.front(); Q.pop(); for(int i = head[u]; ~i ; i = edge[i].next){ int v = edge[i].to; if(edge[i].cap <= edge[i].flow || ~dep[v]) continue; dep[v] = dep[u] + 1; Q.push(v); } } return ~dep[t]; } inline int dfs(int s,int a,int t){ if(s == t || !a) return a; int flow = 0; for(int &i = pre[s]; ~i && a; i = edge[i].next){ int v = edge[i].to; if(dep[v] != dep[s] + 1) continue; int f = dfs(v,min(a,edge[i].cap - edge[i].flow),t); if(!f) continue; flow += f; edge[i].flow += f; edge[i ^ 1].flow -= f; a -= f; } return flow; } int maxflow(int s,int t){ int flow = 0; while(BFS(s,t)){ for(int i = 0 ; i <= 60; i ++) pre[i] = head[i]; flow += dfs(s,INF,t); } return flow; } int cnt; void Init(){ for(int i = 1; i <= 2520; i ++){ int t = 0; for(int j = 0 ; j < 10; j ++) if(!(i % (j + 1))) t |= (1 << j); vis[t]++; Hash[i] = t; } cnt = 0; for(int i = 0; i < (1 << 11); i ++){ if(vis[i]){ road[++cnt] = mp(i,vis[i]); vis[i] = cnt; } } } int main(){ Init(); int T = read(); while(T--){ N = read(); int S = 59,T = 60; init(); for(int i = 1; i <= 10; i ++) add(S,i,read()); int k = N / 2520; N %= 2520; for(int i = 1; i <= 48; i ++) num[i] = 0; for(int i = 1; i <= N ; i ++) num[vis[Hash[i]]]++; for(int i = 1; i <= cnt; i ++){ int id = i + 10,state = road[i].fi; int w = road[i].se * k + num[i]; for(int j = 0 ; j < 10; j ++) if(state & (1 << j)) add(j + 1,id,w); add(id,T,w); } Prl(maxflow(S,T)); } return 0; }
E.线段树维护区间乘,由于质数的存在,要给质数也取模,用费马小定理
质数取的模为mod - 1
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 1e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K,Q; struct Tree{ int l,r; LL sum,lazy1,lazy2; }tree[maxn << 2]; void Pushup(int t){ tree[t].sum = (tree[t << 1].sum * tree[t << 1 | 1].sum) % mod; } void Build(int t,int l,int r){ tree[t].l = l; tree[t].r = r; tree[t].lazy1 = tree[t].lazy2 = 1; tree[t].sum = 0; if(l == r){ tree[t].sum = read() % mod; return; } int m = l + r >> 1; Build(t << 1,l,m); Build(t << 1 | 1,m + 1,r); Pushup(t); } LL cul(LL a,LL b){ LL ans = 1; while(b){ if(b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } void change1(int t,LL v){ tree[t].lazy1 = (v * tree[t].lazy1) % mod; tree[t].sum = tree[t].sum * cul(v,tree[t].r - tree[t].l + 1) % mod; } void Pushdown1(int t){ if(tree[t].lazy1 != 1){ change1(t << 1,tree[t].lazy1); change1(t << 1 | 1,tree[t].lazy1); tree[t].lazy1 = 1; } } void change2(int t,int k){ tree[t].sum = cul(tree[t].sum,k); tree[t].lazy1 = cul(tree[t].lazy1,k); tree[t].lazy2 = tree[t].lazy2 * k % (mod - 1); } void Pushdown2(int t){ if(tree[t].lazy2 != 1){ change2(t << 1,tree[t].lazy2); change2(t << 1 | 1,tree[t].lazy2); tree[t].lazy2 = 1; } } void Pushdown(int t){ Pushdown2(t); Pushdown1(t); } void update1(int t,int l,int r,LL v){ if(l <= tree[t].l && tree[t].r <= r){ change1(t,v); return; } Pushdown(t); int m = (tree[t].l + tree[t].r) >> 1; if(r <= m) update1(t << 1,l,r,v); else if(l > m) update1(t << 1 | 1,l,r,v); else{ update1(t << 1,l,m,v); update1(t << 1 | 1,m + 1,r,v); } Pushup(t); } void update2(int t,int l,int r,LL k){ if(l <= tree[t].l && tree[t].r <= r){ change2(t,k); return; } Pushdown(t); int m = (tree[t].l + tree[t].r) >> 1; if(r <= m) update2(t << 1,l,r,k); else if(l > m) update2(t << 1 | 1,l,r,k); else{ update2(t << 1,l,m,k); update2(t << 1 | 1,m + 1,r,k); } Pushup(t); } LL query(int t,int l,int r){ if(l <= tree[t].l && tree[t].r <= r) return tree[t].sum; Pushdown(t); int m = (tree[t].l + tree[t].r) >> 1; if(r <= m) return query(t << 1,l,r); else if(l > m) return query(t << 1 | 1,l,r); else{ return query(t << 1,l,m) * query(t << 1 | 1,m + 1,r) % mod; } } int main(){ int T = read(); while(T--){ Sca2(N,Q); Build(1,1,N); for(int i = 1; i <= Q; i ++){ int op,l,r; Sca3(op,l,r); if(op == 1) update1(1,l,r,read()); else if(op == 2) update2(1,l,r,read()); else Prl(query(1,l,r)); } } return 0; }
H 最小生成树 + 路径最大值
由于起点和终点都是固定的食物点,所以记dis[i]为i点距离最近的食物点的位置,将最小生成树的边(u,v,w)变为(u,v,w + dis[u] + dis[v]),表示想要经过这条道路最少的食物上限是多少,对于整个图求一个最小生成树,u到v的食物上限就是树链上面的最大边,可用树剖或者倍增lca的思想求得
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 2e5 + 10; const int maxm = 4e5 + 10; const LL INF = 1e18; const int mod = 1e9 + 7; int N,M,K; LL dis[maxn]; struct node{ int p; LL w; node(int p,LL w):p(p),w(w){} friend bool operator < (node a,node b){ return a.w > b.w; } }; struct Edge{ int to,next; LL dis; }edge[maxm * 2]; int head[maxn],tot,tree[maxn]; void init(){ for(int i = 1; i <= N ; i ++) head[i] = -1; for(int i = 1; i <= N ; i ++) tree[i] = i; tot = 0; } void add(int u,int v,LL w){ edge[tot].to = v; edge[tot].next = head[u]; edge[tot].dis = w; head[u] = tot++; } struct E{ int u,v; LL w; E(){} E(int u,int v,LL w):u(u),v(v),w(w){} }e[maxm * 2]; bool cmp(E a,E b){ return a.w < b.w; } int find(int x){ if(x == tree[x]) return x; return tree[x] = find(tree[x]); } void Union(int a,int b){ a = find(a); b = find(b); if(a == b) return; tree[a] = b; } const int SP = 20; int fa[maxn][SP],dep[maxn]; LL pa[maxn][SP]; bool vis[maxn]; void dfs(int t,int la){ vis[t] = 1; for(int i = 1; i < SP; i ++){ fa[t][i] = fa[fa[t][i - 1]][i - 1]; pa[t][i] = max(pa[t][i - 1],pa[fa[t][i - 1]][i - 1]); } for(int i = head[t]; ~i ; i = edge[i].next){ int v = edge[i].to; if(v == la) continue; dep[v] = dep[t] + 1; pa[v][0] = edge[i].dis; fa[v][0] = t; dfs(v,t); } } LL lca(int u,int v){ if(dep[u] < dep[v]) swap(u,v); int t = dep[u] - dep[v]; LL ans = 0; for(int i = 0 ; i < SP; i ++) { if(t & (1 << i)){ ans = max(ans,pa[u][i]); u = fa[u][i]; } } if(u == v) return ans; for(int i = SP - 1; i >= 0 ; i --){ int uu = fa[u][i],vv = fa[v][i]; if(uu != vv){ ans = max(ans,pa[u][i]); ans = max(ans,pa[v][i]); u = uu; v = vv; } } return max(ans,max(pa[v][0],pa[u][0])); } int main(){ Sca2(N,M); init(); for(int i = 1; i <= N ; i ++) dis[i] = INF; priority_queue<node>Q; for(int i = 1; i <= N ; i ++){ if(read()){ dis[i] = 0; Q.push(node(i,0)); } } for(int i = 1; i <= M; i ++){ int u,v; Sca2(u,v); LL w; Scl(w); add(u,v,w); add(v,u,w); e[i] = E(u,v,w); } while(!Q.empty()){ node u = Q.top(); Q.pop(); if(u.w > dis[u.p]) continue; for(int i = head[u.p]; ~i ; i = edge[i].next){ int v = edge[i].to; if(dis[v] > u.w + edge[i].dis){ dis[v] = u.w + edge[i].dis; Q.push(node(v,dis[v])); } } } for(int i = 1; i <= M; i ++) e[i].w += dis[e[i].u] + dis[e[i].v]; for(int i = 1; i <= N; i ++) head[i] = -1; tot = 0; sort(e + 1,e + M + 1,cmp); for(int i = 1; i <= M ; i ++){ if(find(e[i].u) != find(e[i].v)){ Union(e[i].u,e[i].v); add(e[i].v,e[i].u,e[i].w); add(e[i].u,e[i].v,e[i].w); } } for(int i = 1; i <= N ; i ++) if(!vis[i]) dfs(i,0); int T = read(); for(int i = 1; i <= T; i ++){ int u,v; Sca2(u,v); Prl(lca(u,v)); } return 0; }
J 先写出n3的暴力,枚举i,j两个点之后依次遍历长度
考虑到二元组(i,j)转换到(i + 1,j + 1)可延续长度为l - 1的信息,记录一个数组len[maxn][maxn]更新到这两个端点时候的最小长度来优化即可。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 1010; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,P; LL V; LL a[maxn],b[maxn]; int len[maxn][maxn]; LL num[maxn][maxn]; LL cul(LL a){ if(a < 0) a = -a; if(P == 1) return a; else if(P == 2) return a * a; return a * a * a; } int main(){ int T = read(); while(T--){ scanf("%d%lld%d",&N,&V,&P); for(int i = 1; i <= N ; i ++){ for(int j = 1; j <= N ; j ++){ len[i][j] = num[i][j] = 0; } } for(int i = 1; i <= N ; i ++) Scl(a[i]); for(int i = 1; i <= N ; i ++) Scl(b[i]); LL ans = 0; for(int i = 1; i <= N ; i ++){ for(int j = 1; j <= N; j ++){ int l = len[i][j]; LL sum = num[i][j]; ans += l; while(i + l <= N && j + l <= N && sum + cul(a[i + l] - b[j + l]) <= V){ sum += cul(a[i + l] - b[j + l]); ans++; l++; } if(!l) continue; len[i + 1][j + 1] = l - 1; num[i + 1][j + 1] = sum - cul(a[i] - b[j]); } } Prl(ans); } return 0; }