[冬令营模拟]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})\)种,那么可以用一个双向链表维护儿子的所有取值以及该取值的个数,那么对儿子节点修改一个值就是\( ...
随机推荐
- 【BZOJ5037】[Jsoi2014]电信网络 最大权闭合图
[BZOJ5037][Jsoi2014]电信网络 Description JYY创建的电信公司,垄断着整个JSOI王国的电信网络.JYY在JSOI王国里建造了很多的通信基站.目前所有的基站都是使用2G ...
- POJ 1113 Wall【凸包周长】
题目: http://poj.org/problem?id=1113 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...
- 九度OJ 1335:闯迷宫 (BFS)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1782 解决:483 题目描述: sun所在学校每年都要举行电脑节,今年电脑节有一个新的趣味比赛项目叫做闯迷宫. sun的室友在帮电脑节设计 ...
- 【python】-- 队列(Queue)、生产者消费者模型
队列(Queue) 在多个线程之间安全的交换数据信息,队列在多线程编程中特别有用 队列的好处: 提高双方的效率,你只需要把数据放到队列中,中间去干别的事情. 完成了程序的解耦性,两者关系依赖性没有不大 ...
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)
正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piec ...
- 16.Django提交表单
Django表单提交一共有三种方式: 1.不使用Django组件进行提交 2.使用django.forms.Form(所有表单类的父类)进行提交 3.使用django.forms.ModelForm( ...
- LigerUI隐藏列
frozen: true 加入这个属性,此列不会在页面显示
- 阿里云centos7搭建php+nginx环境
阿里云Centos搭建lnmp(php7.1+nginx+mysql5.7) https://jingyan.baidu.com/article/215817f7a10bfb1eda14238b.ht ...
- java访问微信接口发送消息
最近在开发activiti流程的时候有个需求:流程到达每个审批节点后,需要向该节点的审批人发送一个消息,提示有审批需要处理. 参考了一下微信的开发者文档和网络上的一些技术博客,现在记录一下.以便后续继 ...
- java使用poi读写Excel
package com.demo.excel; import com.demo.pojo.Student; import org.apache.poi.hssf.usermodel.HSSFCell; ...