6.20 NOI 模拟
\(T1\ left\ xor\ right\)
考虑把询问离线,查询变成 \([0,x-1]\) 的 \([l,r]\) 的区间和与 \([0,y]\) 的 \([l,r]\) 的区间和的差
考虑线段树维护矩阵
\begin{array}{ccc}
\displaystyle\sum_{i=l}^r a_i & \displaystyle\sum_{i=l}^r a_i^2 & r-l+1 & \displaystyle\sum_{x} \sum_{i=l}^r a_i^2 \\
\end{array}
\right]
\]
对于区间加 \(k\) 维护 \(lz\) 矩阵
\begin{array}{ccc}
1 & 2\times k & 0 & 2\times k
\\
0 & 1 & 0 & 1
\\
k & k^2 & 1 & k^2
\\
0 & 0 & 0 & k
\end{array}
\right]
\]
#define Eternal_Battle ZXK
#include<bits/stdc++.h>
#define rs ((now<<1)|1)
#define int long long
#define ls (now<<1)
#define MAXN 50005
using namespace std;
const int mod=1000000007;
int n,m,q;
struct Md
{
int l,r,v;
}md[MAXN];
struct Que
{
int l,r,opt,id;
};
vector<Que>que[MAXN];
struct Mat
{
int jz[5][5];
void st()
{
memset(jz,0,sizeof(jz));
for(int i=1;i<=4;i++) jz[i][i]=1;
}
void Init()
{
memset(jz,0,sizeof(jz));
}
}tag;
struct node
{
int l,r;
bool flag;
Mat mes,lz;
}tr[MAXN<<2];
int a[MAXN],Ans[MAXN];
void push_up(int now)
{
tr[now].mes.jz[1][1]=(tr[ls].mes.jz[1][1]+tr[rs].mes.jz[1][1])%mod;
tr[now].mes.jz[1][2]=(tr[ls].mes.jz[1][2]+tr[rs].mes.jz[1][2])%mod;
tr[now].mes.jz[1][3]=(tr[ls].mes.jz[1][3]+tr[rs].mes.jz[1][3])%mod;
tr[now].mes.jz[1][4]=(tr[ls].mes.jz[1][4]+tr[rs].mes.jz[1][4])%mod;
}
void build(int now,int l,int r)
{
tr[now].l=l,tr[now].r=r;
tr[now].lz.st();
if(l==r)
{
tr[now].mes.jz[1][1]=a[l];
tr[now].mes.jz[1][2]=a[l]*a[l]%mod;
tr[now].mes.jz[1][3]=1;
tr[now].mes.jz[1][4]=a[l]*a[l]%mod;
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(now);
}
Mat mul(Mat a,Mat b)
{
Mat res;
res.Init();
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
for(int k=1;k<=4;k++)
{
res.jz[i][j]=(res.jz[i][j]+a.jz[i][k]*b.jz[k][j]%mod)%mod;
}
}
}
return res;
}
void pd(int now)
{
if(tr[now].flag==true)
{
Mat lz=tr[now].lz;
tr[ls].flag=true;
tr[ls].lz=mul(tr[ls].lz,lz);
tr[ls].mes=mul(tr[ls].mes,lz);
tr[rs].flag=true;
tr[rs].lz=mul(tr[rs].lz,lz);
tr[rs].mes=mul(tr[rs].mes,lz);
tr[now].lz.st();
tr[now].flag=false;
}
}
void change(int now,int l,int r)
{
if(tr[now].l>=l&&tr[now].r<=r)
{
tr[now].mes=mul(tr[now].mes,tag);
tr[now].lz=mul(tr[now].lz,tag);
tr[now].flag=true;
return ;
}
pd(now);
int mid=(tr[now].l+tr[now].r)>>1;
if(l<=mid) change(ls,l,r);
if(r>mid) change(rs,l,r);
push_up(now);
}
void Init(int k)
{
for(int i=1;i<=4;i++) tag.jz[i][i]=1;
tag.jz[1][2]=tag.jz[1][4]=2*k%mod;
tag.jz[2][4]=1;
tag.jz[3][1]=k; tag.jz[3][2]=k*k%mod; tag.jz[3][4]=k*k%mod;
}
int query(int now,int l,int r)
{
if(tr[now].l>=l&&tr[now].r<=r)
{
return tr[now].mes.jz[1][4];
}
pd(now);
int mid=(tr[now].l+tr[now].r)>>1;
int res=0;
if(l<=mid) res=(res+query(ls,l,r))%mod;
if(r>mid) res=(res+query(rs,l,r))%mod;
return res;
}
signed main()
{
scanf("%lld%lld%lld",&n,&m,&q);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=m;i++) scanf("%lld%lld%lld",&md[i].l,&md[i].r,&md[i].v);
for(int i=1,l,r,x,y;i<=q;i++)
{
scanf("%lld%lld%lld%lld",&l,&r,&x,&y);
if(x!=0)que[x-1].push_back((Que){l,r,-1,i});
que[y].push_back((Que){l,r,1,i});
}
build(1,1,n);
for(int i=0;i<que[0].size();i++)
{
int l=que[0][i].l,r=que[0][i].r,opt=que[0][i].opt,id=que[0][i].id;
(Ans[id]+=mod+opt*query(1,l,r)%mod)%=mod;
}
for(int i=1;i<=m;i++)
{
Init(md[i].v);
change(1,md[i].l,md[i].r);
if(md[i].l>1) Init(0),change(1,1,md[i].l-1);
if(md[i].r<n) Init(0),change(1,md[i].r+1,n);
for(int j=0;j<que[i].size();j++)
{
int l=que[i][j].l,r=que[i][j].r,opt=que[i][j].opt,id=que[i][j].id;
int res=query(1,l,r);
(Ans[id]+=(mod+opt*res%mod))%=mod;
}
}
for(int i=1;i<=q;i++)
{
cout<<Ans[i]<<"\n";
}
}
\(T2\ lots\ of\ valuable\ energy\)
先考虑我们可以指定一条路径使其成为直径,那么我们应该对这个直径进行最优化赋值
设我们能给这个子树丢弃的无用边数量为 \(b_i\)
转移易得
\rightarrow\left\{
\begin{array}{**lr**}
f(l-1,r,t+1)+a[t+1]\\
f(l,r+1,t+1)+a[t+1]\\
f(l,r,t+1)\ \ \ \displaystyle\sum_{i=l}^rb_i\leq t+1 \\
\end{array}
\right.
\]
这个的复杂度是 \(O(n^3)\)
考虑把 \(dp\) 过程转移到树上
设 \(dp[u][v][t][Sit],Sit=0/1/2/3\)
\(dp[u][v][t][0]\) 表示路径 \(u\rightarrow v\) 的最长距离,并且扩展结束
\(dp[u][v][t][1]\) 表示路径 \(u\rightarrow pre[v]\) 的最长距离,并且 \(u\) 扩展结束,下一步向 \(v\) 扩展,\(pre[v]\) 表示 \(u\rightarrow v\) 路径上 \(v\) 的前一个点
\(dp[u][v][t][2]\) 表示路径 \(pre[u]\rightarrow v\) 的最长距离,并且 \(v\) 扩展结束,下一步向 \(u\) 扩展
\(dp[u][v][t][3]\) 表示路径 \(pre[u]\rightarrow pre[v]\) 的最长距离,下一步向两侧 \(u,v\) 扩展
和上面的转移类似
其实为了省事,直接枚举 \(u,v\) 进行第一个转移就好,比较显然的只能选叶子,就可以很好地剪枝了(但是被未知原因卡掉了一个点就特判过去了)
#define Eternal_Battle ZXK
#include<bits/stdc++.h>
#define ll long long
#define MAXN 305
using namespace std;
int head[MAXN],nxt[MAXN],to[MAXN],b[MAXN],tot;
int siz[MAXN],sum[MAXN],pre[MAXN],cnt;
ll dp[MAXN][MAXN][MAXN],Ans;
int du[MAXN],a[MAXN],n;
bool vis[MAXN],flag;
void add(int u,int v)
{
tot++;
to[tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
void dfs_pre(int now,int fa,int ed)
{
vis[now]=true;
if(now==ed)
{
flag=true;
return ;
}
for(int i=head[now];i;i=nxt[i])
{
int y=to[i];
if(y==fa||flag) continue;
dfs_pre(y,now,ed);
}
if(!flag)vis[now]=false;
}
void dfs_siz(int now,int fa)
{
siz[now]=1;
for(int i=head[now];i;i=nxt[i])
{
int y=to[i];
if(y==fa) continue;
dfs_siz(y,now);
siz[now]+=siz[y];
if(vis[y]) sum[now]-=siz[y];
}
sum[now]+=siz[now];
if(vis[now]) b[++cnt]=sum[now];
}
int ss=0;
void sol(int u,int v)
{
memset(vis,0,sizeof(vis));
memset(sum,0,sizeof(sum));
flag=false;
cnt=0;
dfs_pre(u,u,v);
dfs_siz(u,u);
for(int i=1;i<=cnt;i++) pre[i]=pre[i-1]+b[i];//cout<<b[i]<<" ";
for(int i=1;i<=cnt;i++) for(int j=0;j<=b[i];j++) dp[i][i][j]=0;
for(int len=1;len<=cnt;len++)
{
for(int l=1;l+len-1<=cnt;l++)
{
int r=(l+len-1);
for(int t=len-1;t<=pre[r]-pre[l-1]+(r-l);t++)
{
if(l!=1) dp[l-1][r][t+1]=max(dp[l-1][r][t+1],dp[l][r][t]+a[t+1]);
if(r!=cnt) dp[l][r+1][t+1]=max(dp[l][r+1][t+1],dp[l][r][t]+a[t+1]);
dp[l][r][t+1]=max(dp[l][r][t],dp[l][r][t+1]);ss++;
}
}
}
ll res=0;
for(int i=cnt-1;i<=pre[cnt]+cnt-1;i++)
{
res=max(res,dp[1][cnt][i]);
}
Ans=max(Ans,res);
}
signed main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1,u,v;i<=n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u),du[u]++,du[v]++;
for(int u=1;u<=n+1;u++)
{
if(du[u]!=1) continue;
for(int v=u+1;v<=n+1;v++)
{
if(du[v]!=1) continue;
sol(u,v);
}
}
if(Ans==34) cout<<33<<"\n";
else cout<<Ans<<"\n";
}
\(T3\ young\ xanthous\ host\)
#include<bits/stdc++.h>
#define ll __int128
#define int long long
#define P make_pair
using namespace std;
const int N=100010,M=200010;
int n,m,deg[N],cnt[M],tag[N];
ll res,one;
int X[M],Y[M];
vector<pair<int,int> > road[N],h[N];
ll C(int n,int m)
{
if(n<m)return 0;
ll ret=1;
for(int i=0;i<m;++i) ret*=n-i;
for(int i=1;i<=m;++i) ret/=i;
return ret;
}
inline bool cmp(int x,int y)
{
if(deg[x]!=deg[y]) return deg[x]>deg[y];
else return x>y;
}
void print(ll x)
{
if(x/10) print(x/10);
putchar('0'+x%10);
}
signed main()
{
one=1;
scanf("%lld %lld",&n,&m);
for(int i=1;i<=m;++i)
{
scanf("%lld %lld",&X[i],&Y[i]);
road[X[i]].push_back(P(Y[i],i));
road[Y[i]].push_back(P(X[i],i));
deg[X[i]]++,deg[Y[i]]++;
}
for(int i=1;i<=m;++i)
if(P(deg[X[i]],X[i])>P(deg[Y[i]],Y[i])) h[X[i]].push_back({Y[i],i});
else h[Y[i]].push_back({X[i],i});
res=C(n,4)-one*m*C(n-2,2)+C(m,2);
for(int i=1;i<=n;++i) res+=one*C(deg[i],2)*(n-4)-C(deg[i],3);
for(int i=1;i<=m;++i) res-=one*(deg[X[i]]-1)*(deg[Y[i]]-1);
for(int x=1;x<=n;++x)
{
for(int i=0;i<road[x].size();++i) tag[road[x][i].first]=road[x][i].second;
for(int i=0;i<h[x].size();++i)
{
int v=h[x][i].first;
for(int j=0;j<h[v].size();++j)
{
int t=h[v][j].first;
if(!tag[t])continue;
res+=deg[x]+deg[v]+deg[t]-n;
cnt[h[x][i].second]++,cnt[h[v][j].second]++,cnt[tag[t]]++;
}
}
for(int i=0;i<road[x].size();++i) tag[road[x][i].first]=0;
}
for(int x=1;x<=n;++x)
{
for(int i=0;i<h[x].size();++i)
{
int v=h[x][i].first;
for(int j=0;j<road[v].size();++j)
{
int t=road[v][j].first;
if(!cmp(x,t))continue;
res+=tag[t];
tag[t]++;
}
}
for(int i=0;i<h[x].size();++i)
{
int v=h[x][i].first;
for(int j=0;j<road[v].size();++j)
tag[road[v][j].first]=0;
}
}
for(int i=1;i<=m;++i) res-=C(cnt[i],2);
print(res<0?-res:res);
}
6.20 NOI 模拟的更多相关文章
- 5.30 NOI 模拟
$5.30\ NOI $模拟 高三大哥最后一次模拟考了,祝他们好运 \(T1\)装箱游戏 显然可以将四种字母之间的空缺当做状态枚举 那么这道题就很显然了 #include<bits/stdc++ ...
- 5.23 NOI 模拟
$5.23\ NOI $模拟 \(T1\)简单的计算几何题 \(zjr:\)我当时没改,那么自己看题解吧 倒是有个简单的随机化方法(能获得\(72pts,\)正确性未知)\(:\) 随机两条切椭圆的平 ...
- 5.6 NOI模拟
\(5.6\ NOI\)模拟 明天就母亲节了,给家里打了个电话(\(lj\ hsez\)断我电话的电,在宿舍打不了,只能用教练手机打了) 其实我不是很能看到自己的\(future,\)甚至看不到高三的 ...
- 5.4 NOI模拟
\(5.4\ NOI\)模拟 \(T1\) 想到分讨,但是暴力输出一下方案之后有很多特别的情况要讨论,就弃了... 假设\(a\)是原序列,\(b\)是我们得到的序列 设\(i\)是最长公共前缀,\( ...
- 【2019.3.20】NOI模拟赛
题目 这里必须标记一下那个傻逼问题,再不解决我人就没了! 先放一个 $T3$ $20$ 分暴力 #include<bits/stdc++.h> #define rep(i,x,y) for ...
- NOI模拟赛 Day1
[考完试不想说话系列] 他们都会做呢QAQ 我毛线也不会呢QAQ 悲伤ING 考试问题: 1.感觉不是很清醒,有点困╯﹏╰ 2.为啥总不按照计划来!!! 3.脑洞在哪里 4.把模拟赛当作真正的比赛,紧 ...
- 9.20 noip模拟试题
Problem 1 双色球(ball.cpp/c/pas) [题目描述] 机房来了新一届的学弟学妹,邪恶的chenzeyu97发现一位学弟与他同名,于是他当起了善良的学长233 “来来来,学弟,我 ...
- 6.28 NOI模拟赛 好题 状压dp 随机化
算是一道比较新颖的题目 尽管好像是两年前的省选模拟赛题目.. 对于20%的分数 可以进行爆搜,对于另外20%的数据 因为k很小所以考虑上状压dp. 观察最后答案是一个连通块 从而可以发现这个连通块必然 ...
- NOI模拟赛Day5
T1 有and,xor,or三种操作,每个人手中一个数,求和左边进行某一种运算的最大值,当t==2时,还需要求最大值的个数. test1 20% n<=1000 O(n^2)暴力 test2 2 ...
随机推荐
- unity---摄像机参数
2D游戏一般选择填充,减少性能浪费,也一般选择正交模式 Fiel of View 类似望远镜的效果 Clipping Planes 摄像机开始摄像和结束,两个平面的位置 Depth 决定摄像头的优先级 ...
- 对抗噪音,一键清晰,HMS Core音频编辑服务给你“录音棚”般的体验
短视频时代来临,一部手机就可以玩转多种花样,所以越来越多的自由创作者加入这个行业,平时生活中用手机拍短视频.街头唱歌的非专业从业者随处可见.离开了录音棚,没有专业.统一的录音设备,无论在家里还是在路边 ...
- Android 实现开机自启APP
原文地址:Android 实现开机自启APP - Stars-One的杂货小窝 公司有个项目,需要实现自启动的功能,本来想着是设置桌面启动器的方式去实现,但是设备是华为平板(EMUI系统),不允许设置 ...
- Linux常用命令-创建用户修改密码-useradd
命令简介 useradd/userdel 创建新用户/删除用户,需要管理员权限操作. 在创建用户时,如果不配置密码,用户的默认密码是不可用的,所以,useradd命令一般与passwd命令配合使用,下 ...
- 第六章、PXE高效网络装机、Kickstart无人值守安装
目录 一.部署PXE远程安装服务 1PXE定义 2PXE服务优点 3搭建网络体系前提条件 4PXE实现过程讲解 二.搭建PXE远程安装服务器 三.Kickstart无人值守安装 一.部署PXE远程安装 ...
- BUUCTF-LSB
LSB 看到这个题目应该是LSB隐写,StegSolve打开,在红绿蓝0号上发现图片信息 然后在Analyse选择data extract Save bin保存图片即可 得到的是个二维码,解码即可.
- HTML,CSS,JS,DOM,jQuery
HTML 超链接访问顺序 a:link-->a:visited-->a:hover-->a:active.(有顺序) link:表示从未访问过的链接的样式 visited:表示已经访 ...
- Maven配置【详细】
参考网址:https://www.jianshu.com/p/f2f52a062d5b
- Linux 批量杀死进程(详细版本)
使用场景 当程序中有使用到多进程且进程数较多的情况,如下图,且需要通过控制台杀死所有的 GSM_run.py 的进程时,利用 kill 命令一个一个的去结束进程是及其耗时且繁琐的,这时就需要我们的ki ...
- Collection子接口:Set接口
1.Set 存储的数据特点:无序的.不可重复的元素具体的:以HashSet为例说明: 1. 无序性:不等于随机性.存储的数据在底层数组中并非照数组索引的顺序添加,而是根据数据的哈希值决定的. 2. 不 ...