高一上十一月上旬日记
11.1
闲话
- 补
。补完了英语。 - 下午大课间时
突然跟我们说让回班拿冲锋衣,今年就不发冬季校服了。
做题纪要
11.2
闲话
- 上午补
。补完了语文和数学。 - 临吃午饭时突然被
通知吃饭时间又改成了 。 - 详见 2024 NOIP 游记 11.2 。
- 下午
又说吃饭时间调整了,早饭时间为 ,午饭时间为 ,晚饭时间为 ,与隔壁高二的保持一致;让我们补一下没写完的 作业,然后写 搜索、模拟 。 - 晚上的全体奥赛生大会
没让我们去开,需要领奖的同学(指去年 一等的 @K8He 和 @jijidawang 和 @wkh2008 )他找人代替领奖了。
做题纪要
CF372A Counting Kangaroos is Fun
-
再次猜测答案上界在
左右,双指针扫一遍即可。点击查看代码
int a[500010]; int main() { int n,ans=0,l,r,i; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]; } sort(a+1,a+1+n); for(l=n/2,r=n;l>=1;l--) { if(a[r]>=a[l]*2) { ans++; r--; } } cout<<n-ans<<endl; return 0; }
luogu P11242 碧树
-
画图手摸下样例即可。
点击查看代码
int a[100010]; int main() { int n,i; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]; } sort(a+1,a+1+n); for(i=1;i<=n;i++) { if(a[i]==a[n]) { cout<<a[n]-1+(i-1)+(n-i+1)<<endl; break; } } return 0; }
luogu P5305 [GXOI/GZOI2019] 旧词
luogu P3084 [USACO13OPEN] Photo G
-
差分约束。需要
优化 加卡时即可。 -
不保证正确性,被叉了属于正常现象。
点击查看代码
struct node { int nxt,to,w; }e[600010]; int head[600010],vis[600010],dis[600010],num[600010],cnt=0; void add(int u,int v,int w) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; e[cnt].w=w; head[u]=cnt; } void spfa(int s,int n) { memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); deque<int>q; dis[s]=0; vis[s]=1; q.push_back(s); int tot=0; while(q.empty()==0) { int x=q.front(); vis[x]=0; q.pop_front(); for(int i=head[x];i!=0;i=e[i].nxt) { if(dis[e[i].to]>dis[x]+e[i].w) { dis[e[i].to]=dis[x]+e[i].w; num[e[i].to]=num[x]+1; tot++; if(num[e[i].to]>=n+1||tot>=50000000) { cout<<"-1"<<endl; exit(0); } if(vis[e[i].to]==0) { if(q.empty()==0&&dis[e[i].to]>=dis[q.front()]) { q.push_back(e[i].to); } else { q.push_front(e[i].to); } vis[e[i].to]=1; } } } } } int main() { int n,m,l,r,i; cin>>n>>m; for(i=1;i<=m;i++) { cin>>l>>r; add(l-1,r,1); add(r,l-1,-1); } for(i=1;i<=n;i++) { add(i-1,i,1); add(i,i-1,0); } spfa(0,n+1); cout<<dis[n]<<endl; return 0; }
11.3
闲话
- 早上有体活,让
到机房。 - 上午
打学校 的模拟赛。 - 打完模拟赛后
突然跟我们说准备把我们都合并到一个机房去,让我们把机房里的 资料都拿到厕所旁的拐角杂物间去,到杂物间后发现里面堆着“大头电脑”、洗手池和一堆乱七八搜的东西,仅剩空间且没多少了。午饭 让 去吃饭。 - 下午放 @lxyt_415x 的每日一歌《经过》。讲题时看了眼隔壁机房,在把 @5k_sync_closer 等人分走后还是不够我们坐的地方,回来后问
说什么时候合并机房,他说就最多两天以内,让我们做好心理准备。 - 临吃晚饭时铃声还是
打铃,然后找 说把晚饭时间改了,然后又将铃声改成了正常上课的铃声。 - 晚上让 @lxyt_415x 找
申请激情演唱,然后 就同意了,接着我们就偷偷到机房门口偷听了, 还称“唱得还挺好听”。 - 详见 2024 CSP-S 游记 11.3 。
做题纪要
HZTG2082. 最短路
HZTG2080. 玩游戏
11.4
闲话
- 候操时被通知操前班呼由
精神变成了“六无六不”的前三句。 - 早读时
过来问我们为啥来了不早读,然后让我们“激情早读”。 - 吃完早饭回机房后
跟隔壁说今天没有模拟赛,写 字符串 。我们从门外听见后开始“欢呼雀跃”, 随即问我们要干什么,说今天有模拟赛,他正在组。但我们跟他说昨天题还没改完,然后 了下我们改题效率慢(指需要两天改一场模拟赛),然后就取消了今天的模拟赛。 - 从学校
上得知我们打的学校 模拟赛叫“加赛”。 - 详见 2024 CSP-S 游记 11.4 。
- 临吃午饭时
跟我们说让去吃午饭的时候把电脑直接关机,下午来了后直接按照新座位表就坐,但我们没找到新座位表。 - 下午到机房后发现座位表直接贴在了两个机房的黑板上,原合并至一个机房的计划改成了分成两个机房(据说是按照模拟赛成绩分
层)。然后放 @hh弟中弟 的每日一歌《爱的飞行日记》,由 @hh弟中弟 和 @DanhengYinyue 激情演唱,演唱时四个教练都在听,唱的时候 让我们也像听演唱会一样跟着唱。然后 收集了下坏掉的键盘和鼠标。 - 现在左边是 @lxyt_415x ,右边是 @luobotianle 。
- 晚上 @lxyt_415x 哼歌被
了。
做题纪要
luogu P4899 [IOI2018] werewolf 狼人
-
翻译过来就是询问是否存在一条从
到 的路径使得先只经过编号 的点,再只经过编号 的点。 -
考虑建两棵
重构树。第一棵以每条边端点编号的较小值为边权建立重构树(最大生成树),第二棵以每条边端点编号的较大值为边权建立重构树(最小生成树)。 -
新建出的虚点的点权自然要用边权代替。然后就可以在第一棵重构树上倍增找到点权
的最浅的节点,在第二棵重构树上倍增找到点权 的最浅的节点。这两个节点子树内部所有原图中的点就是可行路径上的点。 -
接着需要判断是否有可行的中转点同时在两棵子树内部,主席树维护二维数点判交集即可。
-
具体地,以第一棵子树的
序为下标,以第二棵子树的 序为权值插入主席树即可。点击查看代码
int p[400010]; pair<int,int>E[400010]; bool cmp1(pair<int,int> a,pair<int,int>b) { return min(a.first,a.second)>min(b.first,b.second); } bool cmp2(pair<int,int> a,pair<int,int>b) { return max(a.first,a.second)<max(b.first,b.second); } struct DSU { int fa[400010]; void init(int n) { for(int i=1;i<=n;i++) { fa[i]=i; } } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } }D; struct Gragh { struct node { int nxt,to; }e[800010]; int head[400010],fa[400010][25],dfn[400010],out[400010],c[400010],cnt=0,tim=0; void add(int u,int v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs(int x,int father) { tim++; dfn[x]=tim; fa[x][0]=father; for(int i=1;i<=20;i++) { fa[x][i]=fa[fa[x][i-1]][i-1]; } for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father) { dfs(e[i].to,x); } } out[x]=tim; } void kruskal(int n,int m,int pd) { D.init(2*n); if(pd==1) { sort(E+1,E+1+m,cmp1); } else { sort(E+1,E+1+m,cmp2); } for(int i=1,tot=n;i<=m&&tot<=2*n-1;i++) { int x=D.find(E[i].first),y=D.find(E[i].second); if(x!=y) { tot++; if(pd==1) { c[tot]=min(E[i].first,E[i].second); } else { c[tot]=max(E[i].first,E[i].second); } D.fa[x]=D.fa[y]=tot; add(tot,x); add(tot,y); } } } int ask(int x,int val,int pd) { int rt=x; if(pd==1) { for(int i=20;i>=0;i--) { if(fa[rt][i]!=0&&c[fa[rt][i]]>=val) { rt=fa[rt][i]; } } } else { for(int i=20;i>=0;i--) { if(fa[rt][i]!=0&&c[fa[rt][i]]<=val) { rt=fa[rt][i]; } } } return rt; } }A,B; struct PDS_SMT { int root[400010],rt_sum; struct SegmentTree { int ls,rs,sum; }tree[400010<<5]; #define lson(rt) (tree[rt].ls) #define rson(rt) (tree[rt].rs) int build_rt() { rt_sum++; lson(rt_sum)=rson(rt_sum)=tree[rt_sum].sum=0; return rt_sum; } void update(int pre,int &rt,int l,int r,int pos,int val) { rt=build_rt(); tree[rt]=tree[pre]; tree[rt].sum=tree[pre].sum+val; if(l==r) { return; } int mid=(l+r)/2; if(pos<=mid) { update(lson(pre),lson(rt),l,mid,pos,val); } else { update(rson(pre),rson(rt),mid+1,r,pos,val); } } int query(int rt1,int rt2,int l,int r,int x,int y) { if(x<=l&&r<=y) { return tree[rt2].sum-tree[rt1].sum; } int mid=(l+r)/2,ans=0; if(x<=mid) { ans+=query(lson(rt1),lson(rt2),l,mid,x,y); } if(y>mid) { ans+=query(rson(rt1),rson(rt2),mid+1,r,x,y); } return ans; } }T; bool cmp3(int a,int b) { return A.dfn[a]<A.dfn[b]; } int main() { int n,m,q,s,e,l,r,x,y,i; cin>>n>>m>>q; for(i=1;i<=m;i++) { cin>>E[i].first>>E[i].second; E[i].first++; E[i].second++; } A.kruskal(n,m,1); B.kruskal(n,m,2); A.dfs(2*n-1,0); B.dfs(2*n-1,0); for(i=1;i<=2*n-1;i++) { p[i]=i; } sort(p+1,p+1+2*n-1,cmp3); for(i=1;i<=2*n-1;i++) { T.update(T.root[i-1],T.root[i],1,2*n-1,B.dfn[p[i]],p[i]<=n); } for(i=1;i<=q;i++) { cin>>s>>e>>l>>r; s++; e++; l++; r++; x=A.ask(s,l,1); y=B.ask(e,r,2); cout<<(T.query(T.root[A.dfn[x]-1],T.root[A.out[x]],1,2*n-1,B.dfn[y],B.out[y])!=0)<<endl; } return 0; }
LibreOJ 2865. 「IOI2018」狼人
-
改成交互即可。
-
返回
int
类型的数组和获取 是难处理的,不妨用vector
代替。- 但好像 UOJ 407. 【IOI2018】狼人 上直接告诉约定和限制了。
点击查看代码
#include"werewolf.h" int p[400010]; pair<int,int>E[400010]; vector<int>ans; bool cmp1(pair<int,int> a,pair<int,int>b) { return min(a.first,a.second)>min(b.first,b.second); } bool cmp2(pair<int,int> a,pair<int,int>b) { return max(a.first,a.second)<max(b.first,b.second); } struct DSU { int fa[400010]; void init(int n) { for(int i=1;i<=n;i++) { fa[i]=i; } } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } }D; struct Gragh { struct node { int nxt,to; }e[800010]; int head[400010],fa[400010][25],dfn[400010],out[400010],c[400010],cnt=0,tim=0; void add(int u,int v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs(int x,int father) { tim++; dfn[x]=tim; fa[x][0]=father; for(int i=1;i<=20;i++) { fa[x][i]=fa[fa[x][i-1]][i-1]; } for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father) { dfs(e[i].to,x); } } out[x]=tim; } void kruskal(int n,int m,int pd) { D.init(2*n); if(pd==1) { sort(E+1,E+1+m,cmp1); } else { sort(E+1,E+1+m,cmp2); } for(int i=1,tot=n;i<=m&&tot<=2*n-1;i++) { int x=D.find(E[i].first),y=D.find(E[i].second); if(x!=y) { tot++; if(pd==1) { c[tot]=min(E[i].first,E[i].second); } else { c[tot]=max(E[i].first,E[i].second); } D.fa[x]=D.fa[y]=tot; add(tot,x); add(tot,y); } } } int ask(int x,int val,int pd) { int rt=x; if(pd==1) { for(int i=20;i>=0;i--) { if(fa[rt][i]!=0&&c[fa[rt][i]]>=val) { rt=fa[rt][i]; } } } else { for(int i=20;i>=0;i--) { if(fa[rt][i]!=0&&c[fa[rt][i]]<=val) { rt=fa[rt][i]; } } } return rt; } }A,B; struct PDS_SMT { int root[400010],rt_sum; struct SegmentTree { int ls,rs,sum; }tree[400010<<5]; #define lson(rt) (tree[rt].ls) #define rson(rt) (tree[rt].rs) int build_rt() { rt_sum++; lson(rt_sum)=rson(rt_sum)=tree[rt_sum].sum=0; return rt_sum; } void update(int pre,int &rt,int l,int r,int pos,int val) { rt=build_rt(); tree[rt]=tree[pre]; tree[rt].sum=tree[pre].sum+val; if(l==r) { return; } int mid=(l+r)/2; if(pos<=mid) { update(lson(pre),lson(rt),l,mid,pos,val); } else { update(rson(pre),rson(rt),mid+1,r,pos,val); } } int query(int rt1,int rt2,int l,int r,int x,int y) { if(x<=l&&r<=y) { return tree[rt2].sum-tree[rt1].sum; } int mid=(l+r)/2,ans=0; if(x<=mid) { ans+=query(lson(rt1),lson(rt2),l,mid,x,y); } if(y>mid) { ans+=query(rson(rt1),rson(rt2),mid+1,r,x,y); } return ans; } }T; bool cmp3(int a,int b) { return A.dfn[a]<A.dfn[b]; } vector<int> check_validity(int n,vector<int>u,vector<int>v,vector<int>s,vector<int>e,vector<int>l,vector<int>r) { for(int i=0;i<=u.size()-1;i++) { E[i+1]=make_pair(u[i]+1,v[i]+1); } A.kruskal(n,u.size(),1); B.kruskal(n,u.size(),2); A.dfs(2*n-1,0); B.dfs(2*n-1,0); for(int i=1;i<=2*n-1;i++) { p[i]=i; } sort(p+1,p+1+2*n-1,cmp3); for(int i=1;i<=2*n-1;i++) { T.update(T.root[i-1],T.root[i],1,2*n-1,B.dfn[p[i]],p[i]<=n); } for(int i=0;i<=s.size()-1;i++) { int x=A.ask(s[i]+1,l[i]+1,1); int y=B.ask(e[i]+1,r[i]+1,2); ans.push_back(T.query(T.root[A.dfn[x]-1],T.root[A.out[x]],1,2*n-1,B.dfn[y],B.out[y])!=0); } return ans; }
HZTG2081. 排列
luogu P2491 [SDOI2011] 消防
HZTG2083. 矩形
11.5
闲话
- 早读
让站到 再坐下。 - 上午
打 accoders NOI 的模拟赛。 - 中午下课时众人正打算坐电梯下去结果电梯到了后
从里面出来了,我们遂跑到了四楼坐电梯。 - 下午因为高二的信息课和体育课连上了,遂没放每日一歌。讲题的时候
突然说我们如果有不一样的解法私下讨论就行,但我们之前都是直接开麦一起讲的。 - 详见 2024 CSP-S 游记 11.5 。
- 临吃晚饭时被
通知让我和 @lhx 换下位置,可能是因为我和 @lxyt_415x 魔怔太多被他发现了(?)。现在左边是 @Pursuing_OIer ,右边是 @HANGRY_sol 。 - 晚上
来了后说了下高二的宿舍内务通报和违纪情况,说这次他救不了违纪的人,而且自从他上次和年级部闹翻后好像年级部查得更严了(指都开始查样被了); 还用 新给了他们一个口号,说我们大部分可能文采不太好,上次 @zhengchenxi414 写的宣誓词还不错但不能光让一个人写,让我们好好利用自己手头的资源、工具,加强彼此的合作; 说今天题的难度跟 难度接近,要是把这套题放在考前打就更好了。 - 详见 2024 NOIP 游记 11.5 。
做题纪要
luogu P4655 [CEOI2017] Building Bridges
-
设
表示将 和 根柱子连接的最小花费,状态转移方程为 ,边界为 。 -
令
,并拆掉上式的 有 ,其中横坐标 和斜率 都不是单调递增的。 -
仍考虑维护下凸壳,但难点在于如何插入。
-
平衡树维护动态插入的代码过于繁琐,考虑使用
分治维护。- 先
cdq(l,mid)
计算 ,接着按照 这个区间内的决策点建凸壳(建凸壳前需要先按照 为第一、二关键字排序使其单调),并利用这个凸壳更新 。-
提供一组
数据。- 随便随机几组值域较小的数据就出来了。
点击查看 hack 数据
in: 3 1 4 8 4 3 9 ans: 25
-
- 更新时因为决策点已经固定了,就不再需要像普通
一样动态插入决策点了,遂可以先将 中的先按照对应的 排序再使用单调队列更新,也可以直接二分求解。前后两种写法分别对应 luogu P10979 任务安排 2 和 luogu P5785 [SDOI2012] 任务安排 。- 先按照
排序的做法可以一开始就排好序 分治过程中按照和 的大小关系分组。
- 先按照
- 删除
中的决策点后就可以继续递归处理下一步,即cdq(mid+1,r)
。
点击查看代码
ll f[200010],h[200010],w[200010],k[200010],sum[200010],p[200010],tmp[200010]; deque<ll>q; bool cmpk(ll a,ll b) { return k[a]<k[b]; } ll x(ll i) { return h[i]; } ll y(ll i) { return f[i]+h[i]*h[i]-sum[i]; } bool cmpx(ll a,ll b) { return (x(a)==x(b))?(y(a)<y(b)):(x(a)<x(b)); } void cdq(ll l,ll r) { if(l==r) { return; } ll mid=(l+r)/2; for(ll i=l,x=l,y=mid+1;i<=r;i++) { if(p[i]<=mid) { tmp[x]=p[i]; x++; } else { tmp[y]=p[i]; y++; } } for(ll i=l;i<=r;i++) { p[i]=tmp[i]; } cdq(l,mid); q.clear(); for(ll i=l;i<=mid;i++) { while(q.size()>=2&&(y(q.back())-y(q[q.size()-2]))*(x(p[i])-x(q.back()))>=(y(p[i])-y(q.back()))*(x(q.back())-x(q[q.size()-2]))) { q.pop_back(); } q.push_back(p[i]); } for(ll i=mid+1;i<=r;i++) { while(q.size()>=2&&(y(q[1])-y(q.front()))<=k[p[i]]*(x(q[1])-x(q.front()))) { q.pop_front(); } f[p[i]]=min(f[p[i]],f[q.front()]+(h[p[i]]-h[q.front()])*(h[p[i]]-h[q.front()])+sum[p[i]-1]-sum[q.front()]); } cdq(mid+1,r); sort(p+l,p+r+1,cmpx); } int main() { ll n,i; cin>>n; for(i=1;i<=n;i++) { cin>>h[i]; k[i]=h[i]*2; p[i]=i; } for(i=1;i<=n;i++) { cin>>w[i]; sum[i]=sum[i-1]+w[i]; } sort(p+1,p+1+n,cmpk); memset(f,0x3f,sizeof(f)); f[1]=0; cdq(1,n); cout<<f[n]<<endl; return 0; }
- 先
P438. 选彩笔(rgb)
P439. 兵蚁排序(sort)
luogu P4116 Qtree3
-
把编号挂在
序上,然后对 序修改即可。 -
查询时取
序最小的即可。点击查看代码
struct node { int nxt,to; }e[200010]; int head[200010],dfn[200010],siz[200010],dep[200010],fa[200010],son[200010],top[200010],col[200010],pos[200010],cnt=0,tot=0; void add(int u,int v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs1(int x,int father) { siz[x]=1; fa[x]=father; dep[x]=dep[father]+1; for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father) { dfs1(e[i].to,x); siz[x]+=siz[e[i].to]; son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x]; } } } void dfs2(int x,int id) { top[x]=id; tot++; dfn[x]=tot; pos[tot]=x; if(son[x]!=0) { dfs2(son[x],id); for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa[x]&&e[i].to!=son[x]) { dfs2(e[i].to,e[i].to); } } } } struct SMT { struct SegmentTree { int minn; }tree[400010]; int lson(int x) { return x*2; } int rson(int x) { return x*2+1; } void pushup(int rt) { tree[rt].minn=min(tree[lson(rt)].minn,tree[rson(rt)].minn); } void build(int rt,int l,int r) { if(l==r) { tree[rt].minn=0x3f3f3f3f; return; } int mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } void update(int rt,int l,int r,int pos,int val) { if(l==r) { tree[rt].minn=val; return; } int mid=(l+r)/2; if(pos<=mid) { update(lson(rt),l,mid,pos,val); } else { update(rson(rt),mid+1,r,pos,val); } pushup(rt); } int query(int rt,int l,int r,int x,int y) { if(x<=l&&r<=y) { return tree[rt].minn; } int mid=(l+r)/2,ans=0x3f3f3f3f; if(x<=mid) { ans=min(ans,query(lson(rt),l,mid,x,y)); } if(y>mid) { ans=min(ans,query(rson(rt),mid+1,r,x,y)); } return ans; } }T; void update1(int x,int n) { col[x]^=1; T.update(1,1,n,dfn[x],(col[x]==1)?dfn[x]:0x3f3f3f3f); } int query1(int x,int n) { int ans=0x3f3f3f3f; while(top[x]!=1) { ans=min(ans,T.query(1,1,n,dfn[top[x]],dfn[x])); x=fa[top[x]]; } ans=min(ans,T.query(1,1,n,dfn[1],dfn[x])); return (ans==0x3f3f3f3f)?-1:pos[ans]; } int main() { int n,q,u,v,i; cin>>n>>q; for(i=1;i<=n-1;i++) { cin>>u>>v; add(u,v); add(v,u); } dfs1(1,0); dfs2(1,1); T.build(1,1,n); for(i=1;i<=q;i++) { cin>>u>>v; if(u==0) { update1(v,n); } else { cout<<query1(v,n)<<endl; } } return 0; }
P440. 人口局 DBA(dba)
11.6
闲话
- 吃完早饭后
过来问昨天晚上 说的宿舍违纪的人去年级部了吗,然后开始尝试“搜刮”零食。 - 上午
打学校 的模拟赛。 - 下午放 @5k_sync_closer 的每日一歌《蜂鸟》,由 @5k_sync_closer 和 @K8He 激情演唱。然后讲题。
找人来把前几天拿来的挂钩钉在了墙上让我们挂衣服用, 称材料有点劣质。- 临
时 进来问我们怎么讨论时间都在自己做题,做题时间都在各自讨论,这不是有铃声提醒吗。我说我们怎么知道是讨论铃声还是做题铃声,然后 说这是个好问题,就开始 我们不认真看时间表,记不住时间,然后就扯到了高二那边宿舍违纪和早操情况。
做题纪要
HZTG5733. 新的阶乘
HZTG5734. 博弈树
HZTG5735. 划分
luogu P4360 [CEOI2004] 锯木厂选址
-
设
表示把第二个锯木厂建立在第 棵树时的最小花费,状态转移方程为 。 -
考虑费用提前计算,设
,上式等价于 。 -
拆掉
,有 ,其中横坐标 是单调递增的,斜率 是单调递减的。 -
单调队列维护上凸壳即可。
点击查看代码
ll w[200010],d[200010],sum[200010],dis[200010]; deque<ll>q; ll x(ll i) { return sum[i]; } ll y(ll i) { return sum[i]*dis[i]; } int main() { ll n,num=0,ans=0x7f7f7f7f,i; cin>>n; for(i=1;i<=n;i++) { cin>>w[i]>>d[i]; sum[i]=sum[i-1]+w[i]; } for(i=n;i>=1;i--) { dis[i]=dis[i+1]+d[i]; num+=dis[i]*w[i]; } q.push_back(1); for(i=2;i<=n;i++) { while(q.size()>=2&&(y(q[1])-y(q.front()))>=(x(q[1])-x(q.front()))*dis[i]) { q.pop_front(); } ans=min(ans,num-sum[q.front()]*dis[q.front()]-dis[i]*(sum[i]-sum[q.front()])); while(q.size()>=2&&(y(q.back())-y(q[q.size()-2]))*(x(i)-x(q.back()))<=(y(i)-y(q.back()))*(x(q.back())-x(q[q.size()-2]))) { q.pop_back(); } q.push_back(i); } cout<<ans<<endl; return 0; }
luogu P4072 [SDOI2016] 征途
-
比较显然;提前 乘进去避免精度误差;把距离挂在点上,不妨钦定第 天在 地过夜;考虑只统计平方的贡献 -
设
表示第 天在 地过夜的最小代价,状态转移方程为 。 -
设
,上式等价于 。 -
拆掉
,有 ,其中横坐标 和斜率 是单调递增的。 -
对于每个
分别单调队列维护下凸壳即可。 -
最终有
即为所求。点击查看代码
ll d[3010],sum[3010],f[2][3010]; deque<ll>q; ll x(ll k) { return sum[k]; } ll y(ll i,ll k) { return f[i&1][k]+sum[k]*sum[k]; } int main() { ll n,m,i,j; cin>>n>>m; for(i=1;i<=n;i++) { cin>>d[i]; sum[i]=sum[i-1]+d[i]; } memset(f,0x3f,sizeof(f)); for(i=1;i<=n;i++) { f[1][i]=sum[i]*sum[i]; } for(i=2;i<=m;i++) { q.clear(); q.push_back(i-1); for(j=i;j<=n;j++) { while(q.size()>=2&&(y(i-1,q[1])-y(i-1,q.front()))<=(x(q[1])-x(q.front()))*2*sum[j]) { q.pop_front(); } f[i&1][j]=f[(i-1)&1][q.front()]+(sum[j]-sum[q.front()])*(sum[j]-sum[q.front()]); while(q.size()>=2&&(y(i-1,q.back())-y(i-1,q[q.size()-2]))*(x(j)-x(q.back()))>=(y(i-1,j)-y(i-1,q.back()))*(x(q.back())-x(q[q.size()-2]))) { q.pop_back(); } q.push_back(j); } } cout<<m*f[m&1][n]-sum[n]*sum[n]<<endl; return 0; }
11.7
闲话
- 上午
打 accoders NOI 的模拟赛。 - 下午
强调了下机房讨论、宿舍泡面(自己保管好,别被查到就行)、个人卫生问题; 看见 @CuFeO4 的冲锋衣后说 终于给我们做件像样的校服了。 - 吃完晚饭后 @CTHoi 把
机房外门把手弄折了(我之前开就感觉门把手有点松了,没想到真能弄下来), 来了后把涉及到的人员交出去处理了一下,然后就回来 我们这两届是他见过的习惯最差的, 我们 考得分太低了,高一的还好,高二的不好好干事还成天捣蛋、故意把东西用坏。上次 9.20 时他好不容易给个高一的请下假来复习初赛,然后就因为按电梯这事就把高一的都赶回去了,要是他是高二这届的主教练,他早就让他们走了。 - 晚上听多校的讲题。
做题纪要
P470. 图书管理
P472. 函数
P471. 两棵树
luogu P2480 [SDOI2010] 古代猪文
-
等价于求
。 -
观察到指数较大且
是质数,考虑欧拉定理。 -
当
时等价于求 。 -
直接跑
显然可以做,但考虑更加简便的做法。 -
对
进行质因数分解后可以得到 ,分别 计算后用 合并即可。点击查看代码
const ll p=999911659,m[5]={0,2,3,4679,35617}; ll a[5]; ll qpow(ll a,ll b,ll p) { ll ans=1; while(b) { if(b&1) { ans=ans*a%p; } b>>=1; a=a*a%p; } return ans; } ll C(ll n,ll m,ll p) { if(n>=m&&n>=0&&m>=0) { ll up=1,down=1; for(ll i=n-m+1;i<=n;i++) { up=up*i%p; } for(ll i=1;i<=m;i++) { down=down*i%p; } return up*qpow(down,p-2,p)%p; } else { return 0; } } ll lucas(ll n,ll m,ll p) { return (n>=m&&n>=0&&m>=0)?(m?C(n%p,m%p,p)*lucas(n/p,m/p,p)%p:1):0; } void exgcd(ll a,ll b,ll &x,ll &y) { if(b==0) { x=1; y=0; } else { exgcd(b,a%b,y,x); y-=a/b*x; } } ll inv(ll a,ll p) { ll x=0,y=0; exgcd(a,p,x,y); return (x%p+p)%p; } ll crt(ll n) { ll mul=1,r,ans=0; for(ll i=1;i<=n;i++) { mul*=m[i]; } for(ll i=1;i<=n;i++) { r=mul/m[i]; ans=(ans+(a[i]*r%mul)*inv(r,m[i])%mul)%mul; } return ans; } int main() { ll n,g,i,d; cin>>n>>g; if(g%p==0) { cout<<0<<endl; } else { for(i=1;i<=4;i++) { for(d=1;d<=sqrt(n);d++) { if(n%d==0) { if(d*d==n) { a[i]=(a[i]+lucas(n,d,m[i]))%m[i]; } else { a[i]=(a[i]+lucas(n,d,m[i]))%m[i]; a[i]=(a[i]+lucas(n,n/d,m[i]))%m[i]; } } } } cout<<qpow(g,crt(4),p)<<endl; } return 0; }
luogu P7984 [USACO21DEC] Tickets P
-
考虑对票建虚点,从
向 连一条权值为 的边,然后从 向 连一条权值为 的边。 -
建出反图后
和 的路径集合会有重复统计的部分,不妨以 作为初始值然后再进行一遍松弛操作(若没有重复部分就不需要松弛了)。 -
然后就是线段树优化建图板子了。
点击查看代码
struct SMT_Q_BG { ll id[900010],dis[2][900010],d[900010],vis[900010]; vector<pair<ll,ll> >e[900010]; ll lson(ll x) { return x*2; } ll rson(ll x) { return x*2+1; } void build(ll rt,ll l,ll r,ll n) { e[rt+n*4].push_back(make_pair(rt,0)); if(l==r) { id[l]=rt; return; } e[lson(rt)].push_back(make_pair(rt,0)); e[rson(rt)].push_back(make_pair(rt,0)); e[rt+n*4].push_back(make_pair(lson(rt)+n*4,0)); e[rt+n*4].push_back(make_pair(rson(rt)+n*4,0)); ll mid=(l+r)/2; build(lson(rt),l,mid,n); build(rson(rt),mid+1,r,n); } void update(ll rt,ll l,ll r,ll x,ll y,ll pos,ll w,ll n) { if(x<=l&&r<=y) { e[rt].push_back(make_pair(pos+n*8,w)); return; } ll mid=(l+r)/2; if(x<=mid) { update(lson(rt),l,mid,x,y,pos,w,n); } if(y>mid) { update(rson(rt),mid+1,r,x,y,pos,w,n); } } void dijkstra1(ll s,ll id) { memset(vis,0,sizeof(vis)); memset(dis[id],0x3f,sizeof(dis[id])); priority_queue<pair<ll,ll> >q; dis[id][s]=0; q.push(make_pair(-dis[id][s],s)); while(q.empty()==0) { ll x=q.top().second; q.pop(); if(vis[x]==0) { vis[x]=1; for(ll i=0;i<e[x].size();i++) { if(dis[id][e[x][i].first]>dis[id][x]+e[x][i].second) { dis[id][e[x][i].first]=dis[id][x]+e[x][i].second; q.push(make_pair(-dis[id][e[x][i].first],e[x][i].first)); } } } } } void dijkstra2(ll n,ll k) { memset(vis,0,sizeof(vis)); priority_queue<pair<ll,ll> >q; for(ll i=1;i<=8*n+k;i++) { d[i]=dis[0][i]+dis[1][i]; q.push(make_pair(-d[i],i)); } while(q.empty()==0) { ll x=q.top().second; q.pop(); if(vis[x]==0) { vis[x]=1; for(ll i=0;i<e[x].size();i++) { if(d[e[x][i].first]>d[x]+e[x][i].second) { d[e[x][i].first]=d[x]+e[x][i].second; q.push(make_pair(-d[e[x][i].first],e[x][i].first)); } } } } } }T; int main() { ll n,k,c,p,a,b,i; cin>>n>>k; T.build(1,1,n,n); for(i=1;i<=k;i++) { cin>>c>>p>>a>>b; T.e[i+n*8].push_back(make_pair(T.id[c]+n*4,p)); T.update(1,1,n,a,b,i,0,n); } T.dijkstra1(T.id[1],0); T.dijkstra1(T.id[n],1); T.dijkstra2(n,k); for(i=1;i<=n;i++) { cout<<(T.d[T.id[i]]<1e15?T.d[T.id[i]]:-1)<<endl; } return 0; }
11.8
闲话
- 候操时级部让进行期中考试的目标宣誓,但因为上次我们就没参加(某个早预备),遂不知道誓词是啥。
做题纪要
luogu P4408 [NOI2003] 逃学的小孩
-
题目中保证了
,直接套用直径端点的结论即可。点击查看代码
struct node { ll nxt,to,w; }e[200010]; ll head[200010],dep[200010],dis[200010],fa[200010],siz[200010],son[200010],top[200010],cnt=0,tot=0; void add(ll u,ll v,ll w) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; e[cnt].w=w; head[u]=cnt; } void dfs(ll x,ll father,ll w) { dis[x]=dis[father]+w; for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father) { dfs(e[i].to,x,e[i].w); } } } void dfs1(ll x,ll father,ll w) { siz[x]=1; fa[x]=father; dep[x]=dep[father]+1; dis[x]=dis[father]+w; for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father) { dfs1(e[i].to,x,e[i].w); siz[x]+=siz[e[i].to]; son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x]; } } } void dfs2(ll x,ll id) { top[x]=id; if(son[x]!=0) { dfs2(son[x],id); for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa[x]&&e[i].to!=son[x]) { dfs2(e[i].to,e[i].to); } } } } ll lca(ll u,ll v) { while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { u=fa[top[u]]; } else { v=fa[top[v]]; } } return dep[u]<dep[v]?u:v; } ll get_dis(ll u,ll v) { return dis[u]+dis[v]-2*dis[lca(u,v)]; } int main() { ll n,m,u,v,w,ans=0,rt1=0,rt2=0,d,i; cin>>n>>m; for(i=1;i<=n-1;i++) { cin>>u>>v>>w; add(u,v,w); add(v,u,w); } dfs(1,0,0); for(i=1;i<=n;i++) { rt1=(dis[i]>dis[rt1])?i:rt1; } dfs(rt1,0,0); for(i=1;i<=n;i++) { rt2=(dis[i]>dis[rt2])?i:rt2; } d=dis[rt2]; dfs1(1,0,0); dfs2(1,1); for(i=1;i<=n;i++) { ans=max(ans,min(get_dis(i,rt1),get_dis(i,rt2))+d); } cout<<ans<<endl; return 0; }
QOJ 5312.Levenshtein Distance
luogu P4768 [NOI2018] 归程
luogu P4197 Peaks
-
建立
重构树(最小生成树),主席树维护子树内第 大即可。点击查看代码
struct node { int from,to,w; }; int h[200010],dfn[200010],out[200010],pos[200010],c[200010],fa[200010][25],tot=0; vector<node>E; vector<int>e[200010]; void add(int u,int v) { e[u].push_back(v); } bool cmp(node a,node b) { return a.w<b.w; } struct DSU { int fa[200010]; void init(int n) { for(int i=1;i<=n;i++) { fa[i]=i; } } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } }D; void kruskal(int n) { D.init(2*n-1); sort(E.begin(),E.end(),cmp); for(int i=0,tot=n;i<E.size()&&tot<=2*n-1;i++) { int x=D.find(E[i].from),y=D.find(E[i].to); if(x!=y) { tot++; c[tot]=E[i].w; D.fa[x]=D.fa[y]=tot; add(tot,x); add(tot,y); } } } void dfs(int x,int father) { tot++; dfn[x]=tot; pos[tot]=x; fa[x][0]=father; for(int i=1;i<=20;i++) { fa[x][i]=fa[fa[x][i-1]][i-1]; } for(int i=0;i<e[x].size();i++) { if(e[x][i]!=father) { dfs(e[x][i],x); } } out[x]=tot; } int ask(int x,int val) { int rt=x; for(int i=20;i>=0;i--) { if(fa[rt][i]!=0&&c[fa[rt][i]]<=val) { rt=fa[rt][i]; } } return rt; } struct PDS_SMT { int root[200010],rt_sum; struct SegmentTree { int ls,rs,sum; }tree[200010<<5]; #define lson(rt) (tree[rt].ls) #define rson(rt) (tree[rt].rs) int build_rt() { rt_sum++; lson(rt_sum)=rson(rt_sum)=tree[rt_sum].sum=0; return rt_sum; } void update(int pre,int &rt,int l,int r,int pos,int val) { rt=build_rt(); tree[rt]=tree[pre]; tree[rt].sum+=val; if(l==r) { return; } int mid=(l+r)/2; if(pos<=mid) { update(lson(pre),lson(rt),l,mid,pos,val); } else { update(rson(pre),rson(rt),mid+1,r,pos,val); } } int query(int rt1,int rt2,int l,int r,int k) { if(l==r) { return (tree[rt2].sum-tree[rt1].sum>=k)?l:-1; } int mid=(l+r)/2; if(tree[rson(rt2)].sum-tree[rson(rt1)].sum>=k) { return query(rson(rt1),rson(rt2),mid+1,r,k); } else { return query(lson(rt1),lson(rt2),l,mid,k-(tree[rson(rt2)].sum-tree[rson(rt1)].sum)); } } }T; int main() { int n,m,q,u,v,w,i; cin>>n>>m>>q; for(i=1;i<=n;i++) { cin>>h[i]; } for(i=1;i<=m;i++) { cin>>u>>v>>w; E.push_back((node){u,v,w}); } kruskal(n); dfs(2*n-1,0); for(i=1;i<=2*n-1;i++) { T.root[i]=T.root[i-1]; if(pos[i]<=n) { T.update(T.root[i],T.root[i],1,1000000000,h[pos[i]],1); } } for(i=1;i<=q;i++) { cin>>u>>v>>w; u=ask(u,v); cout<<T.query(T.root[dfn[u]-1],T.root[out[u]],1,1000000000,w)<<endl; } return 0; }
UVA1395 苗条的生成树 Slim Span
-
强化版: luogu P4234 最小差值生成树
点击查看代码
struct node { int from,to,w; }e[10010]; bool cmp(node a,node b) { return a.w<b.w; } struct DSU { int fa[510]; void init(int n) { for(int i=1;i<=n;i++) { fa[i]=i; } } int find(int x) { return (fa[x]==x)?x:fa[x]=find(fa[x]); } }D; int main() { int n,m,x,y,cnt,ans,i,j; while(cin>>n>>m) { if(n==0&&m==0) { break; } else { ans=0x3f3f3f3f; for(i=1;i<=m;i++) { cin>>e[i].from>>e[i].to>>e[i].w; } sort(e+1,e+1+m,cmp); for(i=1;i<=m;i++) { D.init(n); cnt=0; for(j=i;j<=m;j++) { x=D.find(e[j].from); y=D.find(e[j].to); if(x!=y) { D.fa[x]=y; cnt++; if(cnt==n-1) { ans=min(ans,e[j].w-e[i].w); break; } } } } cout<<((ans==0x3f3f3f3f)?-1:ans)<<endl; } } return 0; }
P441. 银行的源起(banking)
luogu P1709 [USACO5.5] 隐藏口令 Hidden Password
-
最小表示法板子。
点击查看代码
char s[10000010]; int main() { int n,i,l,r,len; cin>>n; for(i=1;i<=n;i++) { cin>>s[i]; s[n+i]=s[i]; } l=1; r=2; while(l<=n&&r<=n) { len=0; while(len<=n-1&&s[l+len]==s[r+len]) { len++; } if(len==n) { break; } else { if(s[l+len]>s[r+len]) { l+=len+1; l+=(l==r); } else { r+=len+1; r+=(l==r); } } } cout<<min(l,r)-1<<endl; return 0; }
luogu P11253 [GDKOI2023 普及组] 小学生数学
-
是完全积性函数。点击查看代码
const ll p=998244353; ll prime[3000010],inv[20000010],len=0; bool vis[20000010]; ll qpow(ll a,ll b) { ll ans=1; while(b) { if(b&1) { ans=ans*a%p; } b>>=1; a=a*a%p; } return ans; } void isprime(ll n,ll k) { memset(vis,0,sizeof(vis)); inv[1]=1; for(ll i=2;i<=n;i++) { if(vis[i]==0) { len++; prime[len]=i; inv[i]=qpow(qpow(i,k),p-2); } for(ll j=1;j<=len&&i*prime[j]<=n;j++) { vis[i*prime[j]]=1; inv[i*prime[j]]=inv[i]*inv[prime[j]]%p; if(i%prime[j]==0) { break; } } } } int main() { ll n,k,ans=0,mul=1,i; cin>>n>>k; isprime(n,k); for(i=1;i<=n;i++) { mul=mul*i%p; ans=(ans+mul*inv[i]%p)%p; } cout<<ans<<endl; return 0; }
11.9
闲话
- 早操时看见来参观的人了,貌似今天
又有教研活动。 - 上午
打 accoders NOI 的模拟赛。 - 因为模拟赛时间和高二体活时间冲突了,所以让我们中午
吃饭,下午一起补体活。 - 下午听多校的讲题;
先是被头顶的钟表掉下来砸着了腰,后来起身时又被耳机线缠住了腿,称“不要说话了啊,我今天很暴躁”。 - 感觉
有班主任那味了。
做题纪要
P481. 星际联邦
luogu P10743 [SEERC2020] AND = OR
luogu P9488 ZHY 的生成树
-
两点间的距离为 。 -
最小生成树显然是取到下界时的情况,最大生成树自然取到上界即可。
-
具体地,从
向 的质数倍的点连边。需要手动模拟 排序的过程。点击查看代码
int prime[700000],len=0; bool vis[10000010]; void isprime(int n) { memset(vis,0,sizeof(vis)); for(int i=2;i<=n;i++) { if(vis[i]==0) { len++; prime[len]=i; } for(int j=1;j<=len&&i*prime[j]<=n;j++) { vis[i*prime[j]]=1; if(i%prime[j]==0) { break; } } } } struct DSU { int fa[10000010]; void init(int n) { for(int i=1;i<=n;i++) { fa[i]=i; } } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } }D; ll kruskal(int n) { ll ans=0; D.init(n); for(int i=n/2;i>=1;i--) { for(int j=1;j<=len&&i*prime[j]<=n;j++) { int x=D.find(i),y=D.find(i*prime[j]); if(x!=y) { ans+=i; D.fa[x]=y; } } } return ans; } int main() { int n; cin>>n; isprime(n); cout<<kruskal(n)<<endl; return 0; }
P483. 摆烂合唱
11.10
闲话
- 因为下周二要考期中,所以今天没有体活,让
到位。 - 上午
打学校 的模拟赛。 - 下午讲题。
做题纪要
CF2033B Sakurako and Water
CF2025B Binomial Coefficients, Kind Of
CF2030D QED's Favorite Permutation
luogu P11271 「Diligent-OI R1 A」DlgtPattern
-
四个方向分讨。
点击查看代码
int main() { ll x,y,p,q; cin>>x>>y>>p>>q; cout<<min({p,q,x-p,y-q})<<endl; return 0; }
luogu P11272 「Diligent-OI R1 B」DlgtArray
-
分讨
的个数。点击查看代码
int a[1000010],sum[1000010]; int main() { int n,q,l,r,k,i; scanf("%d%d",&n,&q); for(i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } for(i=1;i<=q;i++) { scanf("%d%d%d",&l,&r,&k); if(l==r||k>=r-l+1) { if(k==0) { cout<<0<<endl; } else { cout<<-1<<endl; } } else { if(k==r-l) { if(sum[r]-sum[l-1]==r-l+1) { printf("%d\n",0); } else { printf("%d\n",k-(sum[r]-sum[l-1])); } } else { printf("%d\n",abs(sum[r]-sum[l-1]-k)); } } } return 0; }
luogu P11273 「Diligent-OI R1 C」DlgtRank
-
倒着考虑即可。
点击查看代码
ll a[200010],b[200010],ans[200010]; int main() { ll n,k,i; cin>>n>>k; for(i=1;i<=n;i++) { cin>>a[i]; b[i]=a[i]; } sort(b+1,b+1+n); b[0]=unique(b+1,b+1+n)-(b+1); for(i=b[0]-1;i>=1;i--) { ans[i]=max(0ll,ans[i+1]-(b[i+1]-b[i]-1)/k+1); } for(i=1;i<=n;i++) { cout<<ans[lower_bound(b+1,b+1+b[0],a[i])-b]<<" "; } return 0; }
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18521952,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探