总传送门

T1. [USACO19JAN] Redistricting P

luogu P5202

  • 思路:

    这种每次选出段长有个上限\(k\)的常常是和单调队列有关。

    这里是单调队列优化dp

    不过一开始想不太清有什么单调性。

    发现每次的贡献为\(0/1\)

    因此如果\(i<j\)且\(dp_i<dp_j\)。\(i\)最多就和\(j\)一样贡献直接删去。

    如果\(dp_i=dp_j\)你需要考虑中间段的贡献,决定是否删。

    不过总之我们的目的是让优劣性单调递减(队首最优)

    如果段\([i+1..j]\)中\(cnt('H')>cnt('G')\)在\(i\)能取到时一定会比\(j\)优,所以保留\(i\)

    否则直接弹出\(i\)
  • code:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
char s[N];
int dp[N],sh[N],sg[N];
int Q[N],hd=1,tl;
bool W(int l,int r) {
return (sg[r]-sg[l]>=sh[r]-sh[l]);
}
bool cmp(int x,int y) {return dp[x]==dp[y]?W(x,y):dp[x]>dp[y];}
int main() {
int n,k,l=1,r;
scanf("%d%d",&n,&k);
scanf("%s",s+1);
for(int i=1;i<=n;i++)sh[i]=sh[i-1]+(s[i]=='H'),sg[i]=sg[i-1]+(s[i]=='G');
dp[0]=0;Q[++tl]=0;
for(int i=1;i<=n;i++) {
while(hd<=tl&&Q[hd]+k<i) hd++;
dp[i]=dp[Q[hd]]+W(Q[hd],i);
while(hd<=tl&&cmp(Q[tl],i)) tl--;
Q[++tl]=i;
}
printf("%d\n",dp[n]);
return 0;
}

T2.[USACO20JAN] Cave Paintings P

luogu P6008

  • 思路:

    并查集

    最简单的思路就是从下往上灌水。

    如果某两个节点在\(i+1\)行不连通,在第\(i\)行联通。然后这两个节点在\(i……n\)时是独立的。(如果独立就相当于乘法原理,不独立就会合成同类一起作贡献)

    推广到带权并查集,合并两个联通块价值为它们乘积+1

    当然我考场上想复杂了。

    因为我一直往图论上套(思维僵化,犯了跟noionline一样的错误)。

    不过还是搞了很久,我把它缩点(如果两个点通过往下、左、右走能联通就合成一个点一起作贡献)

    可能因为我这种做法每行横向一段是手动缩点(而不是并查集),就跑的飞快。

    缩点后成为森林,树上dp。(别忘了记录完起点)

    具体缩点写法,(和正常写法很像)到能合并的时机时,加一个新点代表(合并后的点),连向所有每个都能到的下层的节点(下层的森林上的节点已经构造好了)。
  • code:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+5;
const int M=2e6+5;
const int mod=1e9+7;
int n,m,st[M],tp;
char s[N][N];
int tt[N],ct,Ll,Rl,fa[M],nxt[M],to[M],head[M],ecnt,nd,pos[N][N];
void add_edge(int u,int v) {nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
int gt_fa(int u) {return fa[u]==u?u:fa[u]=gt_fa(fa[u]);}
void Union(int u,int v) {fa[gt_fa(u)]=gt_fa(v);}
int rt[M];
void Build() {
bool bg=0;
for(int i=n;i;i--) {
// printf("!%d\n",i);
if(!bg) {
for(int j=1;j<=m;j++) {
if(s[i][j]=='.') {
++nd;fa[nd]=nd;pos[i][j]=nd;
while(s[i][j+1]=='.') {
j++;pos[i][j]=nd;
}
}
}
if(nd){Ll=1;Rl=nd;bg=1;}
continue;
}
for(int j=1;j<=m;j++) {
if(s[i][j]=='.') {
++nd;fa[nd]=nd;pos[i][j]=nd; //tmp node
if(pos[i+1][j])Union(nd,pos[i+1][j]);
while(s[i][j+1]=='.') {
j++;pos[i][j]=nd;if(pos[i+1][j])Union(nd,pos[i+1][j]);
}
}
}
// new node
int nwR=nd;
ct=0;
for(int j=1;j<=m;j++) {
if(s[i][j]=='#') continue;
int x=gt_fa(pos[i][j]);
if(!rt[x]) {rt[x]=++nd;tt[++ct]=x;fa[nd]=nd;}
pos[i][j]=rt[x];
}
for(int j=Ll;j<=Rl;j++) {
int x=gt_fa(j);
if(!rt[x]) st[++tp]=x; //beginning node
else add_edge(rt[x],j);
// printf("%d(%d) %d\n",rt[x],x,j);
}
Ll=nwR+1;Rl=nd;
while(ct) {rt[tt[ct]]=0;ct--;}
// printf("[%d,%d]\n",Ll,Rl);
}
}
ll dp[M];
void DP(int u) {
dp[u]=1;
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
DP(v);
dp[u]=dp[u]*dp[v]%mod;
}
dp[u]++;
}
int main() {
// int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
Build();
ll ans=1;
while(tp) {
int i=st[tp--];
DP(i);ans=ans*dp[i]%mod;
}
printf("%lld",ans);
return 0;
}

T3.[USACO20JAN] Non-Decreasing Subsequences P

P6009

  • 题意:给每一个长为\(n\)的数列,每个数的上限是\(k\),\(Q\)次问\([l_i,r_i]\)内的最长不降子序列的方案数

  • 思路:

    动态dp

    线段树维护\(z[x][y]\)表示上升子序列的权值为从\(x\)到\(y\)的方案数。

    \(O(q\log_2{n}\ k^2)\)

    难写又慢,而且发现玄机(\(q\)是\(n\)的\(20\)倍)

    想要把询问\(q\)复杂度,转到\(n\)上。接下来用到:

    中轴分治(自己乱创的,类似cdq)

    即分治时每次处理跨过\(mid=(l+r)/2\)的区间

    然后这个区间的结果为\(mid\)左边的部分和右边的部分合并起来

    因此要预处理从\(mid\)往左的答案,从\(mid\)往右的答案

    如果处理和查询的每一步是\(O(1)\)的话,这个算法的复杂度是\(O(nlog_2n+q)\)

    这样就能把\(q\)的复杂度转化到\(n\)上呢。

    合并显然需要:

    \(G[i][y]\):(右半边)开始的值为\(y\),前缀\(i\)的总方案数

    \(F[i][y]\):(左半边)结束的值为\(y\),后缀\(i\)的总方案数

    这里只说右半边(\(G\))的做法,\(F\)同理

    方便\(G\)的转移,我们定义\(g[x][y]\)为上面的\(z[x][y]\)的意思

    然后每次新添加\(a_i\)时:只有\(g[y][a_i]\ \ (1<=y<=a_i)\)会受影响。

    要找前面的一个\(z<=a_i\)

    \(g[y][a_i]+=\sum\limits_{z=1}^{a_i}g[y][z]\)

    还要考虑\(a_i\)独立为一个子序列

    \(g[a_i][a_i]++\)

    这样\(O(k^2)\)处理了\(g\)

    \(G[i][y]=\sum\limits_{z=y}^kg[y][z]\) 知道开头\(y\)枚举结尾

    \(O(k^2)\)而且这个跑的挺满的,实际需要\(O(k)\)就可以啦。

    \(G[i-1][y]\)相比\(G[i][y]\)只有在\(y<=a_i\)时,\(g[y][a_i]\)的改变会影响\(G[i][y]\),此时加上\(g[y][a_i]\)的变化量即可。

    总复杂度\(nlognk^2+qk\)而且肯定是跑不满的。

    我翻了翻题解,题解搞了数据结构来优化到\(nklognlogk\)实际上因为数据结构卡死了上限还跑的比我慢很多。

  • code

戳我
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int M=N>>2;
const int K=21;
const int mod=1e9+7;
int a[N],b[N],q,n,k,rev[N],A[N],t1[N],t2[N];
//g[x][y]:(val)[x...y]; G[i][y]:(val)[y...],pre(pos) i
ll g[K][K],f[K][K],G[M][K],F[M][K],sG[M][K],ans[N];
struct query {int l,r;}Q[N];
void gt_gG(int l,int r) {
g[a[l]][a[l]]=G[l][a[l]]=1;
for(int i=l+1;i<=r;i++) {
int ai=a[i];
for(int y=1;y<=ai;y++) {
G[i][y]=G[i-1][y]-g[y][ai];
ll tmp=g[y][ai]+(y==ai);
for(int z=y;z<=ai;z++) tmp+=g[y][z];
g[y][ai]=(tmp%=mod);
G[i][y]=(G[i][y]+tmp)%mod;
}
for(int y=ai+1;y<=k;y++) {G[i][y]=G[i-1][y];}
}
}
void gt_fF(int l,int r) {
f[b[l]][b[l]]=F[l][b[l]]=1;
for(int i=l+1;i<=r;i++) {
int bi=b[i];
for(int y=bi;y<=k;y++) {
F[i][y]=F[i-1][y]-f[bi][y];
ll tmp=f[bi][y]+(y==bi);
for(int z=bi;z<=y;z++) tmp+=f[z][y];
f[bi][y]=(tmp%=mod);
F[i][y]=(F[i][y]+tmp)%mod;
}
for(int y=1;y<bi;y++)F[i][y]=F[i-1][y];
}
}
void Clear(int l,int r,int L,int R) {
for(int i=1;i<=k;i++)for(int j=1;j<=k;j++)g[i][j]=f[i][j]=0;
for(int i=l;i<=r;i++)for(int j=1;j<=k;j++)F[i][j]=0;
for(int i=L;i<=R;i++)for(int j=1;j<=k;j++)sG[i][j]=G[i][j]=0;
}
ll SG(int i,int j) {
if(sG[i][j])return sG[i][j];
for(int y=1;y<=j;y++) sG[i][j]=(sG[i][j]+G[i][y])%mod;
return sG[i][j];
}
void solve(int l,int r,int L,int R) {
int mid=(l+r)>>1;
gt_gG(mid+1,r);gt_fF(rev[mid],rev[l]);
int c1=L,c2=R;
for(int i=L;i<=R;i++) {
int x=A[i];
if(Q[x].l==Q[x].r) ans[x]=2;
else if(Q[x].l>mid) t2[c2--]=x;
else if(Q[x].r<=mid) t1[c1++]=x;
else {
int st=rev[Q[x].l],ed=Q[x].r;
ans[x]=1+SG(ed,k);
for(int yl=1;yl<=k;yl++) {
ans[x]=(ans[x]+F[st][yl]*(SG(ed,k)-SG(ed,yl-1)+1))%mod;
}
}
}
Clear(rev[mid],rev[l],mid+1,r);
if(c1!=L) {
for(int i=L;i<c1;i++) A[i]=t1[i];
solve(l,mid,L,c1-1);
}
if(c2!=R) {
for(int i=R;i>c2;i--) A[i]=t2[i];
solve(mid+1,r,c2+1,R);
}
} int main() {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) {rev[i]=n-i+1;b[rev[i]]=a[i];}
// for(int i=1;i<=n;i++)printf("%d ",b[i]);puts("");
scanf("%d",&q);
for(int i=1;i<=q;i++) {scanf("%d%d",&Q[i].l,&Q[i].r);A[i]=i;}
solve(1,n,1,q);
for(int i=1;i<=q;i++) printf("%lld\n",(ans[i]+mod)%mod);
return 0;
}

清明欢乐赛(USACO选题)的更多相关文章

  1. contesthunter CH Round #64 - MFOI杯水题欢乐赛day1 solve

    http://www.contesthunter.org/contest/CH Round %2364 - MFOI杯水题欢乐赛 day1/Solve Solve CH Round #64 - MFO ...

  2. 2014.8.3情人节欢乐赛【Benny的农场】

    Benny的农场 (farm.pas/.c/.cpp) 时间限制:1s.空间限制:128MB 题目描述: Benny有一片农田需要灌溉.农田的形状为矩形,并被分为许多小块.每一块中都有一些水管.共有1 ...

  3. i春秋第二届春秋欢乐赛RSA256writeup

    i春秋第二届春秋欢乐赛writeup 下载之后进行解压 发现四个文件 0x01看到题目是RSA的  又看到public.key 所以直接用kali linux的openssl 0x02可以看到e就是E ...

  4. 2014-10-24 NOIP欢乐赛

    10-24NOIP欢乐赛 ——By 潘智力 题目名称 分火腿 无聊的会议 班服 时间限制 1s 1s 1s 内存限制 64MB 128MB 128MB 输入文件 hdogs.in meeting.in ...

  5. Comet OJ 夏季欢乐赛 篮球校赛

    Comet OJ 夏季欢乐赛 篮球校赛 题目传送门 题目描述 JWJU注重培养学生的"唱,跳,rap,篮球"能力.于是每年JWJU都会举办篮球校赛,来给同学们一个切磋篮球技术的平台 ...

  6. Comet OJ 夏季欢乐赛 Gree的心房

    Comet OJ 夏季欢乐赛 Gree的心房 题目传送门 题目描述 据说每一个走进Gree哥哥心房的小姑娘都没有能够再走出来-- 我们将Gree哥哥的心房抽象成一个n \times mn×m的地图,初 ...

  7. Comet OJ 夏季欢乐赛 分配学号

    Comet OJ 夏季欢乐赛 H 分配学号 题目传送门 题目描述 今天,是JWJU给同学们分配学号的一天!为了让大家尽可能的得到自己想要的学号,鸡尾酒让大家先从 [1,10^{18}][1,1018] ...

  8. Comet OJ 2019 夏季欢乐赛题解

    Comet OJ 2019 夏季欢乐赛题解 我是来骗访问量的 A 完全k叉树 \(n\)个点的完全k叉树的直径. 直接做 B 距离产生美 直接做 C 烤面包片 \(n!!!\mod p\) 显然\(n ...

  9. 【题解】Comet OJ 国庆欢乐赛 简要题解

    [题解]Comet OJ 国庆欢乐赛 简要题解 A 直接做 B 直接做,结论: \[ ans=\max([Max\ge \mathrm{sum}] Max,s[n]/2) \] C 考虑这样一个做法: ...

随机推荐

  1. mysql基本操作2

    ##DDL控制表结构,不支持事务##DML控制表数据,支持事务       DQL专门做查询  ##TCL 管理事务##DCL 管理数据库权限     ##ORDER BY  子句-根据指定列对结果集 ...

  2. 微信h5支付/jsapi支付/小程序支付

    一. 介绍------------------------------------------------------------------ 微信支付官方开发文档:  https://pay.wei ...

  3. 设计模式学习笔记(十四)责任链模式实现以及在Filter中的应用

    责任链模式(Chain Of Responsibility Design Pattern),也叫做职责链,是将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求.当有请求发生时,可将请求沿着这条 ...

  4. 看完这篇文章你就可以告诉领导你精通Zookeeper了

    一.Zookeeper概述 1.概述 Zookeeper 是一个开源的为分布式框架提供协调服务的 Apache 项目.在分布式系统中,扮演注册中心的角色. Zookeeper数据模型的结构与Linux ...

  5. Model, HttpServletRequest, ModelMap区别

    看了spring mvc的底层会发现,model数据最终还是写到HttpServletRequest属性中,只是model的写法更体现了MVC思想减少各层间耦合 写法: 1.request.setAt ...

  6. Postman大势已去

    作为一名前端,日常开发过程中除了写业务代码,前后端联调更是重要的一环.但这一环却往往是整个开发中最繁琐也最累人的一环.任谁都想早点下班,然而提升联调效率并不是个纯技术相关的问题,而是需要有良好工作流程 ...

  7. 记录:替换线上springboot项目可执行jar包中依赖jar里的class文件

    问题背景: 项目组发现线上版本问题后,定位是由于项目依赖的某个jar包中有个小BUG. 解决方案: 在修改了对应的java文件后,编译出对应的class文件.从生产环境下载项目jar包,解压后,找到对 ...

  8. PowerBI开发:用自然语言来探索数据--Q&A

    Power BI报表的用户,肯定会被Q&A的功能惊艳到,在查看报表时,仅仅通过输入文本就可以探索数据,并且结果是可视化的,更令人惊艳的时,结果几乎是实时显示出来的.这使得Q&A Vis ...

  9. TCP 连接的建立 & 断开

    TCP 连接的建立过程 一开始,客户端和服务端都处于 close 状态. 先是服务端监听某个端口,此时服务端处于 listen 状态. 这个时候客户端就可以发送连接请求报文了. 第一次握手 客户端会主 ...

  10. 【Java分享客栈】一文搞定CompletableFuture并行处理,成倍缩短查询时间。

    前言   工作中你可能会遇到很多这样的场景,一个接口,要从其他几个service调用查询方法,分别获取到需要的值之后再封装数据返回.   还可能在微服务中遇到类似的情况,某个服务的接口,要使用好几次f ...