[冬令营模拟]wzj的题目#1
T1 少膜一个,T3 暴力写挂
强势 rank1 -> rank2
一场比赛两道线段树分治,给力
T1 password
给你 m 个禁止字符串,求长度为 n 的所有字符串中至少包含这些禁止字符串各一次的字符串数量
$n \leq 10^9,m \leq 4,\sum len \leq 50$
sol:容斥一下就变成了“m 个禁止字符串,一个都不出现的字符串数量”
这个可以转化成从 init 节点走 x 步走不到任意一个节点的方案数
矩阵加速即可
需要注意的是状态压缩被卡了,这种状压 + 矩乘可以用容斥来把矩阵变小
比赛的时候因为少膜了一下,挂了一个点
- #include<bits/stdc++.h>
- #define int long long
- #define LL long long
- using namespace std;
- inline int read()
- {
- int x = ,f = ;char ch = getchar();
- for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
- for(;isdigit(ch);ch = getchar())x = * x + ch - '';
- return x * f;
- }
- const int N = ;
- const int A = ;
- const int MOD = ;
- typedef vector<int> vec;
- typedef vector<vec> mat;
- mat mul(mat &A, mat &B)
- {
- mat C(A.size(), vec(B[].size()));
- for (int i = ; i < A.size(); ++i)
- {
- for (int k = ; k < B.size(); ++k)
- {
- for (int j = ; j < B[].size(); ++j)
- {
- C[i][j] = (C[i][j] + (LL)A[i][k] * B[k][j]) % MOD;
- }
- }
- }
- return C;
- }
- mat pow(mat A, int n)
- {
- mat B(A.size(), vec(A.size()));
- for (int i = ; i < A.size(); ++i)
- B[i][i] = ;
- while (n > )
- {
- if (n & ) B = mul(B, A);
- A = mul(A, A);
- n >>= ;
- }
- return B;
- }
- struct ACAutomata
- {
- int next[N][A], fail[N], end[N];
- int root, L;
- int idx(char ch)
- {
- return ch - '';
- }
- int newNode()
- {
- for (int i = ; i < A; ++i) next[L][i] = -;
- end[L] = ;
- return L++;
- }
- void init()
- {
- L = ;
- root = newNode();
- }
- void insert(char buf[])
- {
- int len = strlen(buf);
- int now = root;
- for (int i = ; i < len; ++i)
- {
- int ch = idx(buf[i]);
- if (next[now][ch] == -) next[now][ch] = newNode();
- now = next[now][ch];
- }
- end[now]++;
- }
- void build()
- {
- queue<int> Q;
- fail[root] = root;
- for (int i = ; i < A; ++i)
- {
- if (next[root][i] == -)
- {
- next[root][i] = root;
- }
- else
- {
- fail[ next[root][i] ] = root;
- Q.push( next[root][i] );
- }
- }
- while (!Q.empty())
- {
- int now = Q.front();
- Q.pop();
- if (end[ fail[now] ]) end[now]++;
- for (int i = ; i < A; ++i)
- {
- if (next[now][i] == -)
- {
- next[now][i] = next[ fail[now] ][i];
- }
- else
- {
- fail[ next[now][i] ] = next[ fail[now] ][i];
- Q.push(next[now][i]);
- }
- }
- }
- }
- int query(int n)
- {
- mat F(L, vec(L));
- for (int i = ; i < L; ++i)
- {
- for (int j = ; j < L; ++j)
- {
- F[i][j] = ;
- }
- }
- for (int i = ; i < L; ++i)
- {
- for (int j = ; j < A; ++j)
- {
- int nt = next[i][j];
- if (!end[nt]) F[i][nt]++;
- }
- }
- F = pow(F, n);
- int res = ;
- for (int i = ; i < L; ++i)
- {
- res = (res + F[][i]) % MOD;
- }
- return res;
- }
- } ac;
- int m,n;
- char buf[][];
- int skr(int x,int t)
- {
- int res = ;
- while(t)
- {
- if(t & )res = res * x % MOD;
- x = x * x % MOD;
- t = t >> ;
- }return res;
- }
- signed main()
- {
- freopen("password.in","r",stdin);
- freopen("password.out","w",stdout);
- m = read(),n = read();
- int qwq = ,qnq = skr(,n);
- for(int i=;i<=m;i++)cin>>buf[i];
- for(int SS=;SS<=(<<m)-;SS++)
- {
- int flg = __builtin_popcount(SS),S = (flg & ) ? : -;
- ac.init();
- memset(ac.next,-,sizeof(ac.next));
- memset(ac.fail,,sizeof(ac.fail));
- memset(ac.end,,sizeof(ac.end));
- for(int i=;i<m;i++)
- if(SS & ( << i))ac.insert(buf[i+]);
- ac.build();
- qwq += (S * ac.query(n));
- }
- cout<<((((qnq-qwq) % MOD) + MOD) % MOD)<<endl;
- return ;
- }
T1
T2 paint
APIO2014 特别行动队,但是所有东西都可以为负
额...就是你现在有 n 个人,每个人有权值,你可以把它们分成若干组,第 i 人只能跟 $[i-l,i+r]$ 这些人一组,一组的权值和为 $s$,一组的权值为 $ax^2+bx+c$ ,让你最大化权值
sol:因为一个人只能由 $[i-l,i+r]$ 转移过来,我们可以考虑这个人有贡献的区间,那显然是 $[i+l,min(i+r,n)]$ ,我们可以在线段树这个区间上打上这个人的 tag
然后我们按线段树的 dfs 序扫这个区间,因为这个人有贡献的区间一定在这个人右边,所以处理到这个区间的时候,所有打在上面的 tag 已经处理完毕了
于是我们可以把从这个叶子到根的 logn 层凸包并起来二分
然后就写完了。。
- #include<bits/stdc++.h>
- #define LL long long
- #define DB long double
- using namespace std;
- inline int read()
- {
- int x = ,f = ;char ch = getchar();
- for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
- for(;isdigit(ch);ch = getchar())x = * x + ch - '';
- return x * f;
- }
- const int maxn = ;
- const DB inf = (DB)1.0 / 0.0;
- int n,l,r;
- LL a,b,c;
- LL sum[maxn],f[maxn];
- void force()
- {
- for(int i=;i<=n;i++)
- {
- for(int j=max(i-r,);j<=min(i-l,n);j++)
- f[i] = max(f[i],f[j] + a * (sum[i] - sum[j]) * (sum[i] - sum[j]) + b * (sum[i] - sum[j]) + c);
- }
- cout<<f[n]<<endl;
- }
- struct point
- {
- DB x,y;
- int id;
- point operator - (const point &b)const{return (point){x - b.x,y - b.y,id};}
- bool operator < (const point &b)const{return x < b.x;}
- DB operator * (const point &b)const{return x * b.y - y * b.x;}
- }ps[maxn];
- vector<int> Items[maxn << ],ch[maxn << ];
- DB dp[maxn],Sum[maxn];
- int q[maxn],top;
- #define ls (x << 1)
- #define rs ((x << 1) | 1)
- void Insert(int x, int l, int r, int L, int R, int id)
- {
- if(L <= l && r <= R){Items[x].push_back(id);return;}
- int mid = (l + r) >> ;
- if(L <= mid) Insert(ls,l,mid,L,R,id);
- if(R > mid) Insert(rs,mid + ,r,L,R,id);
- }
- inline DB trans(int frm,int targ){return (DB)dp[frm] + (DB)a * (Sum[targ] - Sum[frm]) * (Sum[targ] - Sum[frm]) + (DB)b * (Sum[targ] - Sum[frm]) + c;}
- void CDQ(int x,int l,int r)
- {
- int tp = ;
- for(int i=;i<Items[x].size();i++)
- {
- int to = Items[x][i];
- ps[++tp] = (point){Sum[to],dp[to] + (DB)a * Sum[to] * Sum[to] - (DB)b * Sum[to],to};
- }
- if(tp)
- {
- sort(ps + ,ps + tp + );top = ;
- q[++top] = ;
- for(;q[] <= tp && ps[q[]].y == -inf;++q[]);
- for(int i=q[]+;i<=tp;i++)
- {
- if(ps[i].y == -inf) continue;
- for(;top > && ((ps[q[top]] - ps[q[top-]]) * (ps[i] - ps[q[top]])) >= ;--top);
- q[++top] = i;
- }
- if(q[] > tp)top = ;
- for(;top && ps[q[top]].y == -inf;--top);
- if(top)for(int i=;i<=top;i++)ch[x].push_back(ps[q[i]].id);
- }
- if(l == r)
- {
- int now = x;
- while(now)
- {
- int nl = ,nr = ch[now].size() - ;
- while(nl < nr)
- {
- int md = (nl + nr) >> ;
- if(md < (ch[now].size() - ) && trans(ch[now][md],l) <= trans(ch[now][md+],l))nl = md + ;
- else nr = md;
- }
- if(ch[now].size())dp[l] = max(dp[l],trans(ch[now][nl],l));
- now = now >> ;
- }
- return;
- }
- int mid = (l + r) >> ;
- CDQ(ls,l,mid);CDQ(rs,mid + ,r);
- }
- void solve()
- {
- for(int i=;i<=n;i++)Sum[i] = sum[i];
- for(int i=;i<=n;i++)dp[i] = -inf;
- for(int i=;i<=n;i++)Insert(,,n,i + l,min(i+r,n),i);
- //cout<<111<<endl;
- CDQ(,,n);LL ans = floor(dp[n]);
- printf("%lld\n",ans);
- //cout<<ret<<endl;
- }
- int main()
- {
- freopen("paint.in","r",stdin);
- freopen("paint.out","w",stdout);
- n = read();a = read();b = read();c = read();l = read();r = read();
- for(int i=;i<=n;i++)sum[i] = sum[i - ] + read();
- //if(n <= 1000)force();
- //else
- solve();
- }
T2
T3 route
树上找一条链,满足
1.链上最长边和最短边的差不超过 m
2.链上最短边 $\times$ 链上边权和 最大
$n,m \leq 2 \times 10^5$
sol:
如果没有 m 的限制,就是一个点分治
对于分治中心往下的每一条链,我们记一个信息 $(mi,su)$ 表示这条链上最小值为 $mi$ ,权值和为 $su$
按 $mi$ 的下标插入树状数组,每次查询即可
注意每次按儿子顺序正着做一遍,反着做一遍·
这样写可以 $O(nlog^2n)$ 拿到 80 分
或者我们用 LCT 维护子树信息,很好想但。。。不太可写
正解基于下面一个结论:如果树上一个连通块 u 的一条直径为 $u_i,u_j$ ,一个连通块 v 的一条直径为 $v_i,v_j$
则 $(u_i,v_i),(u_i,v_j),(u_j,v_i),(u_j,v_j)$ 其中至少一个为连通块 u,v 的并集的直径
于是对于 80 分我们可以按从大到小加入每条边然后直接统计答案
对于 100 分,除了加入,我们还有删除操作
这个时候我们可以线段树按时间分治,用一个可撤销的并查集来维护连通性
或者 LCT
- #include<cstdio>
- #include<cctype>
- #include<queue>
- #include<ctime>
- #include<cstring>
- #include<algorithm>
- #define dwn(i,s,t) for(int i=s;i>=t;i--)
- #define rep(i,s,t) for(int i=s;i<=t;i++)
- #define ren for(int i=first[x];i;i=next[i])
- using namespace std;
- inline int read() {
- int x=,f=;char c=getchar();
- for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
- for(;isdigit(c);c=getchar()) x=x*+c-'';
- return x*f;
- }
- typedef long long ll;
- typedef pair<int,int> Pair;
- const int maxn=;
- struct Edge {
- int u,v,w;
- bool operator < (const Edge& ths) const {return w>ths.w;}
- }E[maxn];
- int n,lim,first[maxn],next[maxn<<],dis[maxn<<],to[maxn<<],e;
- void AddEdge(int u,int v,int w) {
- to[++e]=v;dis[e]=w;next[e]=first[u];first[u]=e;
- to[++e]=u;dis[e]=w;next[e]=first[v];first[v]=e;
- }
- ll mn[][maxn*],dep[maxn];
- int pos[maxn*],cnt;
- void dfs(int x,int fa) {
- mn[][++cnt]=dep[x];pos[x]=cnt;
- ren if(to[i]!=fa) {
- dep[to[i]]=dep[x]+dis[i];
- dfs(to[i],x);
- mn[][++cnt]=dep[x];
- }
- }
- int Log[maxn*];
- void init() {
- Log[]=-;rep(i,,cnt) Log[i]=Log[i>>]+;
- for(int j=;(<<j)<=cnt;j++)
- for(int i=;i+(<<j)-<=cnt;i++)
- mn[j][i]=min(mn[j-][i],mn[j-][i+(<<j-)]);
- }
- ll query(int x,int y) {
- ll ans=dep[x]+dep[y];x=pos[x];y=pos[y];if(x>y) swap(x,y);
- int k=Log[y-x+];
- return ans-*min(mn[k][x],mn[k][y-(<<k)+]);
- }
- Pair A[maxn];
- Pair merge(Pair A,Pair B) {
- int x1=A.first,y1=A.second;
- int x2=B.first,y2=B.second;
- int x=x1,y=y1;
- if(query(x2,y2)>query(x,y)) x=x2,y=y2;
- if(query(x2,y1)>query(x,y)) x=x2,y=y1;
- if(query(x2,x1)>query(x,y)) x=x2,y=x1;
- if(query(y2,x1)>query(x,y)) x=y2,y=x1;
- if(query(y2,y1)>query(x,y)) x=y2,y=y1;
- return make_pair(x,y);
- }
- int pa[maxn],size[maxn];
- int findset(int x) {return x==pa[x]?x:findset(pa[x]);}
- int end[maxn];
- struct Data {
- int x,y,pax,sizey;
- ll ansv;
- Pair datay;
- }S[maxn];
- int ToT;
- ll maxlen,ans;
- void link(int x,int y) {
- x=findset(x);y=findset(y);
- if(x==y) return;
- if(size[x]>size[y]) swap(x,y);
- S[++ToT]=(Data){x,y,pa[x],size[y],maxlen,A[y]};
- pa[x]=y;if(size[x]==size[y]) size[y]++;A[y]=merge(A[y],A[x]);
- maxlen=max(maxlen,query(A[y].first,A[y].second));
- }
- void restore(int begin) {
- while(ToT!=begin) {
- int x=S[ToT].x,y=S[ToT].y,pax=S[ToT].pax,sizey=S[ToT].sizey;
- maxlen=S[ToT].ansv;Pair z=S[ToT--].datay;
- pa[x]=pax;size[y]=sizey;A[y]=z;
- }
- }
- int ls[maxn<<],rs[maxn<<],rt;
- void buildtree(int& o,int l,int r) {
- o=++ToT;if(l==r) return;
- int mid=l+r>>;
- buildtree(ls[o],l,mid);buildtree(rs[o],mid+,r);
- }
- int first2[maxn<<],nxt2[maxn*],id[maxn*];
- void AddMark(int x,int val) {
- id[++cnt]=val;nxt2[cnt]=first2[x];first2[x]=cnt;
- }
- void query(int o,int l,int r,int ql,int qr,int val) {
- if(ql<=l&&r<=qr) AddMark(o,val);
- else {
- int mid=l+r>>;
- if(ql<=mid) query(ls[o],l,mid,ql,qr,val);
- if(qr>mid) query(rs[o],mid+,r,ql,qr,val);
- }
- }
- void solve(int o,int l,int r) {
- int begin=ToT;
- for(int i=first2[o];i;i=nxt2[i]) link(E[id[i]].u,E[id[i]].v);
- if(l<r) {
- int mid=l+r>>;
- solve(ls[o],l,mid);
- solve(rs[o],mid+,r);
- }
- else ans=max(ans,maxlen*E[l].w);
- restore(begin);
- }
- int main() {
- freopen("route.in","r",stdin);
- freopen("route.out","w",stdout);
- n=read();lim=read();
- rep(i,,n-) {
- E[i].u=read();E[i].v=read();E[i].w=read();
- AddEdge(E[i].u,E[i].v,E[i].w);
- }
- buildtree(rt,,n-);ToT=;
- dfs(,);init();cnt=;
- sort(E+,E+n);
- rep(i,,n) pa[i]=i,A[i]=make_pair(i,i),size[i]=;
- int j=n-;
- dwn(i,n-,) {
- while(E[i].w-E[j].w>lim) j--;
- end[i]=j;query(rt,,n-,i,end[i],i);
- }
- solve(rt,,n-);
- printf("%lld\n",ans);
- return ;
- }
T3
[冬令营模拟]wzj的题目#1的更多相关文章
- [2018冬令营模拟测试赛(二十一)]Problem A: Decalcomania
[2018冬令营模拟测试赛(二十一)]Problem A: Decalcomania 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见&quo ...
- [冬令营模拟]GTSG2018
上学期没有去 GTSG,于是今天老师让我们来做一下 GTSG2018 Day1 & Day3 Day1 在上午当成一场考试来搞了,Day3 由于锅太多而且 T3 玄学而被放到下午自学... 上 ...
- 6.19 noip模拟题(题目及解析转自 hzwer 2014-3-15 NOIP模拟赛)
Problem 1 高级打字机(type.cpp/c/pas) [题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序 ...
- [JZOJ5977] 【清华2019冬令营模拟12.15】堆
题目 其中n,q≤500000n,q\leq 500000n,q≤500000 题目大意 让你维护一个堆.支持一下操作: 在某个点的下面加上另一个点,然后进行上浮操作. 询问某一点的权值. 思考历程 ...
- JZOJ[5971]【北大2019冬令营模拟12.1】 party(1s,256MB)
题目 题目大意 给你一棵树,在树上的某一些节点上面有人,要用最小的步数和,使得这些人靠在一起.所谓靠在一起,即是任意两个人之间的路径上没有空的节点(也就是连在一起). N≤200N \leq 200N ...
- jzoj5990. 【北大2019冬令营模拟2019.1.6】Bear (状压dp)
题面 题解 我永远讨厌dp.jpg 搞了一个下午优化复杂度最后发现只要有一个小trick就可以A了→_→.全场都插头dp就我一个状压跑得贼慢-- 不难发现我们可以状压,对于每一行,用状态\(S\)表示 ...
- jzoj5991. 【北大2019冬令营模拟2019.1.6】Juice
题面 题解 好迷-- //minamoto #include<bits/stdc++.h> #define R register #define ll long long #define ...
- jzoj5989. 【北大2019冬令营模拟2019.1.6】Forest (set)
题面 题解 为了一点小细节卡了一个下午--我都怕我瞎用set把电脑搞炸-- 观察一次\(1\)操作会造成什么影响,比如说把\(A[i]\)从\(x\)改成\(y\): \(D[x]\)会\(-1\), ...
- jzoj5984. 【北大2019冬令营模拟2019.1.1】仙人掌 (分块)
题面 题解 数据结构做傻了.jpg 考虑每一个节点,它的儿子的取值最多只有\(O(\sqrt {m})\)种,那么可以用一个双向链表维护儿子的所有取值以及该取值的个数,那么对儿子节点修改一个值就是\( ...
随机推荐
- 安装android Studio和运行react native项目(基础篇)
ANDROID_HOME环境变量 确保ANDROID_HOME环境变量正确地指向了你安装的Android SDK的路径. 打开控制面板 -> 系统和安全 -> 系统 -> 高级系统设 ...
- [note]一类位运算求最值问题
[note]一类位运算求最值问题 给定一些数,让你从中选出两个数a,b,每次询问下列中的一个 1.a and b的最大值 2.a xor b的最大值 3.a or b的最大值 神仙们都是FWT,小蒟蒻 ...
- Android系统移植与调试之------->如何修改Android自带的apk出现一圈圈类似鸡蛋的花纹
最近被一个问题烦恼到了,就是android4.1系统自带的Email.文件管理器.信息等apk都出现同一个问题,就是现实在平板上的时候会出现一圈圈类似鸡蛋的花纹. 我想了两种方法来解决,第一种方法没有 ...
- 忘记apple id如何更新应用?
最近ytkah的app有很多更新提示,之前注册的apple id好久没登录了,突然提示说登录需要验证安全问题,哪还记得噢,最要命的是邮箱收到的加密邮件也需要验证.重新注册一个吧,这次要注意保存相关信息 ...
- client = new DatagramSocket(LocalPort) 是说端口已经被占用的意思
ok 现在遇到一个问题,client = new DatagramSocket(LocalPort) 是说端口已经被占用的意思 ref:!!https://community.oracle.com/t ...
- LeetCode:最少移动次数使得数组元素相等||【462】
LeetCode:最少移动次数使得数组元素相等||[462] 题目描述 给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1. 您可以假设数组的长度最 ...
- Linux通过Shell对文件自动进行远程拷贝备份
在执行计划任务拷贝文件的时候,用scp命令需要输入密码,这里用公共密钥的方式实现密码的自动输入. 具体操作: 要求:把192.168.0.2机上的test.tar拷贝到192.168.0.3机器的上 ...
- Python OOP(1)
类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且在函数体之外. ...
- Linux内核源码中的likely和unlikely释疑【转】
本文转载自:https://my.oschina.net/armsky/blog/15320 ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢? 首 ...
- java入门了解15
1.批处理文件(bat) 简单的说,批处理的作用就是自动的连续执行多条命令 .编写bat处理文件可以使用记事本的方式: 常见批处理文件的命令: echo 表示显示此命令后的字符 tiltle 设置窗口 ...