Codeforces 833B The Bakery
第一次做线段树优化dp.没想到div.2的D这么难,以后真的要退竞了.
将一串数字分为k个连续区间,使得每一段中出现数字种数的总和最大.
我们先来思考一下裸的dp.
定义dp[i][j]
为前
个数分割为
份的最大值.
因此有代码
dp[i][j]=max(dp[k=1 to i][j-1])+sum(k,n);
/*此处的sum(k,n)是k to n出现数字的总数.*/
这个sum(k,n)不好处理,如果要强行预处理要n^2的复杂度,不能支持.
对于一个数a[i]
来说,我们需要知道上一个a[i]
出现在哪里.
所以我们要处理一个
数组.
所以有如下代码.
for (i=1;i<=n;++i){
scanf("%d",&a[i]);
pre[i]=pos[a[i]]+1;
pos[a[i]]=i;
}
/*应该可以看懂吧.*/
对于a[i]
来说,它只能在
这段区间内产生1的贡献.(否则与前面出现了重复的数字没有贡献.)
那么用线段树维护区间最大值即可.
ps:一不小心把dp数组打反了re在第8个点.
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
int x=0,f=1;char c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return f?x:-x;
}
inline void read(rel &x){
x=0;int f=1;char c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
x=f?x:-x;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return pc(48);
if (x<0) x=-x,pc('-');
int bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
}
inline char fuhao(){
char c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
const int yuzu=3.5e4;
typedef int fuko[yuzu|10];
typedef int karen[yuzu<<2|13];
int n=read(),k=read();
fuko a,dp[55],pre,pos;
struct segtree{
#define le rt<<1
#define ri le|1
#define ls le,l,mid
#define rs ri,mid+1,r
karen da,lazy;
void init(){
memset(da,0,sizeof da);
memset(lazy,0,sizeof lazy);
}
void build(int d,int rt=1,int l=1,int r=n){
if (l==r) da[rt]=dp[d][l-1];
else{
int mid=l+r>>1;
build(d,ls),build(d,rs);
da[rt]=max(da[le],da[ri]);
}
}
void push_down(int rt,int l,int r){
if (lazy[rt]){
da[le]+=lazy[rt],da[ri]+=lazy[rt];
lazy[le]+=lazy[rt],lazy[ri]+=lazy[rt];
lazy[rt]=0;
}
}
void update(int ql,int qr,int v,int rt=1,int l=1,int r=n){
if (ql>r||qr<l) return;
if (ql<=l&&qr>=r){
da[rt]+=v,lazy[rt]+=v;
}else{
int mid=l+r>>1;
push_down(rt,l,r);
update(ql,qr,v,ls),update(ql,qr,v,rs);
da[rt]=max(da[le],da[ri]);
}
}
int query(int ql,int qr,int rt=1,int l=1,int r=n){
if (ql>r||qr<l) return 0;
if (ql<=l&&qr>=r) return da[rt];
int mid=l+r>>1;
push_down(rt,l,r);
return max(query(ql,qr,ls),query(ql,qr,rs));
}
}my_;
int main(){
re0 i,j;
for (i=1;i<=n;++i){
a[i]=read();
pre[i]=pos[a[i]]+1;
pos[a[i]]=i;
}
for (i=1;i<=k;++i){
my_.init();
my_.build(i-1);
for (j=1;j<=n;++j){
my_.update(pre[j],j,1);
dp[i][j]=my_.query(1,j);
}
}
write(dp[k][n]);
}
Codeforces 633H Fibonacci-ish II
q个询问,每次询问求[l,r]内所有a[i]从小到大排序并去重之后所有F(a[i])的和.
F(a[i])=斐波那契数列的第a[i]项.
本题标算用线段树维护莫队的add和del函数,复杂度
,常数巨大,有时候跑不过
的暴力.
暴力
爆c过去.
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
int x=0,f=1;char c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return f?x:-x;
}
template <typename mitsuha>
inline bool read(mitsuha &x){
x=0;int f=1;char c=gc();
for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
if (!~c) return 0;
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return x=f?x:-x,1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return pc(48);
if (x<0) x=-x,pc('-');
int bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
}
inline char fuhao(){
char c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
#define yi first
#define er second
typedef pair<int,int> pii;
const int yuzu=3e4;
typedef int fuko[yuzu|10];
fuko ans,step,fib={1,1},l,r,last;
int n=read(),m=read();
pii a[yuzu|10];
int main(){
int i,j;
for (i=1;i<=n;++i) a[i]=pii(read(),i);
sort(a+1,a+n+1);
memset(last,-1,sizeof last);
for (i=2;i<=n;++i) fib[i]=(fib[i-1]+fib[i-2])%m;
int q=read();
for (i=1;i<=q;++i) l[i]=read(),r[i]=read();
for (i=1;i<=n;++i){
int d=a[i].yi%m;
for (j=1;j<=q;++j){
if (a[i].er>=l[j]&&a[i].er<=r[j]&&a[i].yi^last[j]){
ans[j]=(ans[j]+fib[step[j]++]*d)%m;
last[j]=a[i].yi;
}
}
}
for (i=1;i<=q;++i) write(ans[i]),pl;
}
Codeforces 522D Closest Equals
q个询问,每次询问区间[l,r]中相距最近的两个相同的数的距离.没有输出-1.
这题非常神.
首先你需要会处理每个数和在它前面离它最近的相同数之间的距离.这个以下几句代码就搞定了.
for (int i=1;i<=n;++i){
/*非常古老的操作了,用过很多遍,大家一定要记下来.注意这个pos数组它是个map.当然你也可以先离散化,但是写起来很难过.*/
int x;scanf("%d",&x);
pre[i]=pos[x];
ord[pos[x]]=i;
pos[x]=i;
v[i]=!pre[i]?inf:i-pre[i];//如果没有前驱的话就设为inf.
}
然后用线段树维护v数组区间的最小值即可.
但是还没有这么简单.如果询问出的答案是由
得到的但
在
的左边,岂不是就错了?
这时不要忘了只有询问.
我们把询问离线,按照左端点排序,这样在询问的时候就可以把
之间的所有
的部分都更新为inf,就能够防止出现上面的情况了.
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
int x=0,f=1;char c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return f?x:-x;
}
template <typename mitsuha>
inline bool read(mitsuha &x){
x=0;int f=1;char c=gc();
for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
if (!~c) return 0;
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return x=f?x:-x,1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return pc(48);
if (x<0) x=-x,pc('-');
int bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
return 0;
}
inline char fuhao(){
char c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
const int yuzu=5e5,inf=0x3f3f3f3f;
typedef int fuko[yuzu|10];
fuko a,pre,x,ans,ord;
map<int,int> pos;
int n=read(),m=read();
struct query{
int l,r,id;
bool operator <(const query &b) const{
return l<b.l;
}
}q[yuzu|10];
typedef int karen[yuzu<<2|13];
struct segtree{
#define le rt<<1
#define ri le|1
#define ls le,l,mid
#define rs ri,mid+1,r
karen xiao;
void build(int rt=1,int l=1,int r=n){
if (l==r) xiao[rt]=x[l];
else{
int mid=l+r>>1;
build(ls),build(rs);
xiao[rt]=min(xiao[le],xiao[ri]);
}
}
void update(int u,int v,int rt=1,int l=1,int r=n){
if (u>r||u<l) return;
if (l==r) xiao[rt]=v;
else{
int mid=l+r>>1;
update(u,v,ls),update(u,v,rs);
xiao[rt]=min(xiao[le],xiao[ri]);
}
}
int query(int ql,int qr,int rt=1,int l=1,int r=n){
if (ql>r||qr<l) return inf;
if (ql<=l&&qr>=r) return xiao[rt];
int mid=l+r>>1;
return min(query(ql,qr,ls),query(ql,qr,rs));
}
}my_;
int main(){
int i;
for (i=1;i<=n;++i){
a[i]=read();
pre[i]=pos[a[i]];
ord[pos[a[i]]]=i;
pos[a[i]]=i;
x[i]=!pre[i]?inf:i-pre[i];
}
my_.build();
for (i=1;i<=m;++i){
q[i].l=read(),q[i].r=read(),q[i].id=i;
}
sort(q+1,q+m+1);
int now=1;
for (i=1;i<=m;++i){
for (;now<q[i].l;my_.update(ord[now++],inf));
int tmp=my_.query(1,q[i].r);
ans[q[i].id]=tmp^inf?tmp:-1;
}
for (i=1;i<=m;++i) write(ans[i]),pl;
}
Codeforces 718C Sasha and Array
我要给这题的出题人打
!这题出得太妙了!
维护区间加,区间F(a[i])和mod(10^9+7).F(x)是第x个斐波那契数.
首先,我们思考一下人生.求第x个斐波那契数模
的值可以用矩阵快速幂.
再看怎么处理
,明显可以得到以下的式子.
令斐波那契数列的转移矩阵为A.
则有F(x)*(A^v)=F(x+v).
接下来问题已经迎刃而解.
我们用普通的维护区间和的线段树,不过这一次节点里储存的
和
不再是数字,而是矩阵.
区间的更新就用矩阵乘法即可.
能想到线段树维护矩阵快速幂,出题人非常厉害,不得不膜拜一下.
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
int x=0,f=1;char c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return f?x:-x;
}
template <typename mitsuha>
inline bool read(mitsuha &x){
x=0;int f=1;char c=gc();
for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
if (!~c) return 0;
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return x=f?x:-x,1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return pc(48);
if (x<0) x=-x,pc('-');
int bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
return 0;
}
inline char fuhao(){
char c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
const int yuzu=1e5,mod=1e9+7;
typedef int fuko[yuzu|10];
int n=read(),m=read();
#define qing0(x) memset(x,0,sizeof x)
struct juzhen{
ll m[3][3];
void clearit(){
qing0(m);
for (int i=1;i<=2;++i) m[i][i]=1;
}
bool judge(){
return m[1][1]==1&&!m[1][2]&&!m[2][1]&&m[2][2]==1;
}
juzhen operator *(const juzhen &a){
int i,j,k;
juzhen ans;
qing0(ans.m);
for (i=1;i<=2;++i){
for (j=1;j<=2;++j){
for (k=1;k<=2;++k){
ans.m[i][j]=(ans.m[i][j]+m[i][k]*a.m[k][j])%mod;
}
}
}return ans;
}
juzhen operator +(const juzhen &b){
int i,j;
juzhen ans;
qing0(ans.m);
for (i=1;i<=2;++i){
for (j=1;j<=2;++j){
ans.m[i][j]=(ans.m[i][j]+m[i][j]+b.m[i][j])%mod;
}
}return ans;
}
void print(){
int i,j;
for (i=1;i<=2;++i,pl){
for (j=1;j<=2;++j,p32) write(m[i][j]);
}
}
}tmp,zero;
juzhen operator ^(juzhen a,ll b){
juzhen ans;ans.clearit();
for (;b;b>>=1,a=a*a)
if (b&1) ans=ans*a;
return ans;
}
typedef juzhen karen[yuzu<<2|13];
struct segtree{
#define le rt<<1
#define ri le|1
#define ls le,l,mid
#define rs ri,mid+1,r
karen val,lazy;
void push_up(int rt){
val[rt]=val[le]+val[ri];
}
void build(int rt=1,int l=1,int r=n){
qing0(val[rt].m);
lazy[rt].clearit();
if (l==r){
int x=read()-1;
juzhen now=tmp^x;
val[rt].m[1][1]=now.m[1][1];
val[rt].m[1][2]=now.m[1][2];
return;
}
int mid=l+r>>1;
build(ls),build(rs);
push_up(rt);
}
void push_down(int rt){
if (!lazy[rt].judge()){
val[le]=val[le]*lazy[rt];
val[ri]=val[ri]*lazy[rt];
lazy[le]=lazy[le]*lazy[rt];
lazy[ri]=lazy[ri]*lazy[rt];
lazy[rt].clearit();
}
}
void update(int ql,int qr,juzhen v,int rt=1,int l=1,int r=n){
if (ql>r||qr<l) return;
if (ql<=l&&qr>=r){
val[rt]=val[rt]*v;
lazy[rt]=lazy[rt]*v;
}else{
int mid=l+r>>1;
push_down(rt);
update(ql,qr,v,ls),update(ql,qr,v,rs);
push_up(rt);
}
}
juzhen query(int ql,int qr,int rt=1,int l=1,int r=n){
if (ql>r||qr<l) return zero;
if (ql<=l&&qr>=r) return val[rt];
int mid=l+r>>1;
push_down(rt);
return query(ql,qr,ls)+query(ql,qr,rs);
}
void dfs(int rt=1,int l=1,int r=n){
printf("#%d %d %d\n",rt,l,r);
val[rt].print();
int mid=l+r>>1;
if (l^r) dfs(ls),dfs(rs);
}
}my_;
int main(){
tmp.m[1][1]=tmp.m[1][2]=tmp.m[2][1]=1;
my_.build();
for (;m--;){
int op=read(),l=read(),r=read();
switch(op){
case 1: my_.update(l,r,tmp^read()); break;
case 2: write(my_.query(l,r).m[1][1]),pl; break;
}
}
}