总传送门

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. js 图片上传给后台的3种格式

    1. file格式 (创建formData来完成file上传) 我们的接口需求: 代码: <input type="file" id="imgfile" ...

  2. 基于nodejs中实现跨域的方法

    一般情况下跨域是通过ajax的方式请求数据,通过js在不同的域之间进行数据传输或者通信: 只有通过ajax方式获取请求的时候才会有跨域问题需要解决: 例如在本地模拟两个服务端. 一个服务端去通过aja ...

  3. ELK日志保留7天-索引生命周期策略

    一.简介 ELK日志我们一般都是按天存储,例如索引名为"kafkalog-2022-04-05",因为日志量所占的存储是非常大的,我们不能一直保存,而是要定期清理旧的,这里就以保留 ...

  4. 蓝桥杯 贪吃蛇长度java实现

    小明在爷爷的私人收藏馆里找到一台老式电脑.居然没有图形界面,只能用控制台编程. 如上图,是游戏时画面截图. 其中,H表示蛇头,T表示蛇尾.#表示蛇的身体,@表示身体交叉重叠的地方. 你能说出现在的贪吃 ...

  5. 嵌入式Servlet容器

    配置嵌入式Servlet容器 ##Spring Boot里面内置了嵌入式的Servlet容器(tomcat) 点击pom.xml->右键->Diagrams->show Depend ...

  6. SpringMVC-开启静态资源访问权限

    1.配置 <mvc:resources mapping="/js/**" location="/js/"/> mapping:代表js目录下的所有文 ...

  7. Oracle安装 - shmmax和shmall设置

    一.概述 在Linux上安装oracle,需要对内核参数进行调整,其中有shmmax和shmall这两个参数,那这两个参数是什么意思,又该如何设置呢? 二.官方文档 在oracle的官方文档( htt ...

  8. [资源] 桃宝上十几块买的C#教程网盘

    我粗略的看了下觉得挺好的,分享给大家 链接:https://pan.baidu.com/s/1iHuLUXde4_L7NB-Zw9JWNg 提取码:1314

  9. BurpSuite下提示embedded browser initialisation failed(嵌入式浏览器初始化失败)的解决方法

    BurpSuite可谓是渗透测试过程经常使用的神器之一,但使用中经常会碰到奇奇怪怪的问题,比如有时抓http包,发送到Repeater(中继器,也叫重发器)模块后,在右边Render模块下,却无法看到 ...

  10. SSM整合_年轻人的第一个增删改查_基础环境搭建

    写在前面 SSM整合_年轻人的第一个增删改查_基础环境搭建 SSM整合_年轻人的第一个增删改查_查找 SSM整合_年轻人的第一个增删改查_新增 SSM整合_年轻人的第一个增删改查_修改 SSM整合_年 ...