传送门
贪心到前面第一个非法位置转移。
#include
using namespace std;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=1e5+50;
int n,a[N],p[N][2],f[N];
int main() {
n=rd();
for(int i=1;i<=n;i++) a[i]=rd();
for(int i=1;i<=n;i++) {
p[i][0]=p[i-1][0];
p[i][1]=p[i-1][1];
if(a[i]>a[i-1]) p[i][1]=i-1;
if(a[i]<a[i-1]) p[i][0]=i-1;
f[i]=f[min(p[i][0],p[i][1])]+1;
} cout<<f[n]<<'\n';
}
随便放一条边在双端队列中,然后不断向两边扩展。
#include
using namespace std;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=2e5+50;
int n,m,inq[N];
vector <int> edge[N];
deque <int> q;
inline void F(int x) {q.push_front(x); inq[x]=1;}
inline void T(int x) {q.push_back(x); inq[x]=1;}
inline bool CF(int x) {
for(auto v:edge[x]) if(!inq[v]) {F(v); return true;}
return false;
}
inline bool CT(int x) {
for(auto v:edge[x]) if(!inq[v]) {T(v); return true;}
return false;
}
int main() {
n=rd(), m=rd();
for(int i=1;i<=m;i++) {
int x=rd(), y=rd();
edge[x].push_back(y);
edge[y].push_back(x);
}
for(int i=1;i<=n;i++) if(edge[i].size()) {F(i), T(edge[i].front()); break;}
while(CF(q.front())); while(CT(q.back()));
printf("%d\n",q.size());
for(auto v:q) printf("%d ",v);
}
最后蚂蚁的位置是确定的,彼此的顺序也是确定的。 每次有蚂蚁经过 0 0 0处排名会整体移动1。
#include
using namespace std;
typedef long long LL;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=1e5+50;
int n,cnt,L,T,a[N],b[N],w[N];
int main() {
n=rd(), L=rd(), T=rd();
for(int i=1;i<=n;i++) {
a[i]=rd(), w[i]=(rd()==1 ? 1 : -1);
b[i]=((a[i]+(LL)T*w[i])%L+L)%L;
int dis=(w[i]>0 ? L-a[i] : a[i])+1;
if(T>=dis) {
cnt+=w[i]; int res=T-dis;
cnt+=(res/L)*w[i];
cnt=(cnt%n+n)%n;
}
} sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
printf("%d\n",b[(i+cnt-1)%n+1]);
}
考虑任意一个序列,他非法一定存在某个位置的前缀超过了范围。
那么DP的时候记录一下是否卡住过范围,就可以不重不漏了。
#include
using namespace std;
typedef long long LL;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=3e3+50, mod=1e9+7;
inline void add(int &x,int y) {x=(x+y>=mod) ? (x+y-mod) : (x+y);}
int n,m,f[N][N][2];
int main() {
n=rd(), m=rd();
for(int i=0;i<=n;i++) f[0][i][i==0]=1;
for(int i=1;i<=m;i++) {
for(int j=0;j<=n;++j) {
if(j) add(f[i][j][j==1],f[i-1][j][0]), add(f[i][j][1],f[i-1][j][1]);
if(j) add(f[i][j-1][j==1],f[i-1][j][0]), add(f[i][j-1][1],f[i-1][j][1]);
if(n-j) add(f[i][j][0],f[i-1][j][0]), add(f[i][j][1],f[i-1][j][1]);
if(n-j) add(f[i][j+1][0],f[i-1][j][0]), add(f[i][j+1][1],f[i-1][j][1]);
}
}
int ans=0;
for(int i=0;i<=n;i++) add(ans,f[m][i][1]);
cout<<ans<<'\n';
}
把问题转化为一个正方形里面可以放两个点,总共的方案数。
矩阵快速幂即可。
#include
using namespace std;
#define rep(i,x,y) for(int i=x;i<=y;i++)
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
int n,m;
const int T1[3][3]={ {2,1,1},
{2,1,2},
{1,0,1} };
const int T2[3][3]={ {1,1,1},
{0,1,2},
{0,0,1} };
struct matrix {
int a[3][3];
matrix (int t=0) {memset(a,0,sizeof(a)); rep(i,0,2) a[i][i]=t;}
friend inline matrix operator *(const matrix &a,const matrix &b) {
matrix c(0);
rep(i,0,2) rep(k,0,2) rep(j,0,2) c.a[i][j]=add(c.a[i][j],mul(a.a[i][k],b.a[k][j]));
return c;
}
friend inline matrix operator ^(matrix a,int b) {
matrix c(1);
for(;b;b>>=1,a=a*a) if(b&1) c=c*a;
return c;
}
} A,tr1,tr2;
int main() {
n=rd(), m=rd();
A.a[0][0]=1;
memcpy(tr1.a,T1,sizeof(T1));
memcpy(tr2.a,T2,sizeof(T2));
int lst=0;
for(int i=1;i<=m;++i) {
int nxt=rd();
A=A*(tr1^(nxt-lst-1));
A=A*tr2; lst=nxt;
}
A=A*(tr1^(n-lst));
cout<<A.a[0][2]<<'\n';
}
注意匹配完之后是一个括号序列。
放入最后一张卡(左括号)之前的后缀和一定形如 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , . . 1,1,1,1,0,0,0,0,.. 1,1,1,1,0,0,0,0,..,我们需要预处理所有 n + 1 n+1 n+1个这样的代价。
先假设全部放在正面,然后从右到左贪心的修改区间,保证每个后缀 ≥ 0 \ge 0 ≥0。 然后再从左往右,贪心保证每个前缀 ≥ 0 \ge 0 ≥0即可。
#include
using namespace std;
#define X first
#define Y second
typedef pair <int,int> pii;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=1e5+50, INF=0x3f3f3f3f;
int n,bz=1,cnt;
int a[N],b[N],c[N],d[N],e[N],ans[N];
struct L {
int l,r;
L(int l,int r) : l(l),r(r) {}
friend inline bool operator <(const L &a,const L &b) {return a.l<b.l || (a.l==b.l && a.r>b.r);}
};
struct R {
int l,r;
R(int l,int r) : l(l),r(r) {}
friend inline bool operator <(const R &a,const R &b) {return a.r<b.r || (a.r==b.r && a.l>b.l);}
};
multiset <int> lq[N];
multiset <int> rq[N];
multiset <L> ls;
multiset <R> rs;
inline int kth(int x) {return lower_bound(c+1,c+n+2,x)-c;}
int main() {
n=rd();
for(int i=1;i<=n;i++) a[i]=rd(), b[i]=rd();
for(int i=1;i<=n+1;i++) c[i]=rd(), d[i]=e[i]=1;
sort(c+1,c+n+2);
for(int i=1;i<=n && bz;i++) {
if(a[i]>c[n+1] && b[i]>c[n+1]) bz=0;
if(a[i]<=c[n+1]) {
a[i]=kth(a[i]); b[i]=kth(b[i]);
--d[a[i]]; --e[a[i]];
if(b[i]<a[i]) rq[a[i]].insert(b[i]+1), lq[b[i]+1].insert(a[i]);
} else --d[kth(b[i])], --e[kth(b[i])], ++cnt;
}
if(!bz) {for(int i=rd();i;i--) puts("-1"); return 0;}
for(int i=n+1;i>=1 && bz;i--) {
d[i]+=d[i+1];
for(auto v:rq[i]) ls.insert(L(v,i));
while(d[i]<0) {
++cnt;
if(!ls.size()) {bz=0; break;}
L t=*ls.begin(); ls.erase(ls.begin());
lq[t.l].erase(lq[t.l].find(t.r));
++d[i]; --d[t.l-1];
++e[t.r]; --e[t.l-1];
}
}
if(!bz) {for(int i=rd();i;i--) puts("-1"); return 0;}
for(int i=n;i>=1;i--) e[i]+=e[i+1];
for(int i=1;i<=n+1;i++) {d[i]=e[i]-e[i-1];}
for(int i=1;i<=n+1 && bz;i++) {
d[i]+=d[i-1];
for(auto v:lq[i]) rs.insert(R(i,v));
while(d[i]<1) {
++cnt;
if(!rs.size()) {bz=0; cnt=INF; for(int j=i+1;j<=n+1;++j) ans[j]=cnt; break;}
R t=*--rs.end(); rs.erase(--rs.end());
++d[i]; --d[t.r+1];
} ans[i]=cnt;
}
for(int i=rd();i;i--) {
int x=rd(), y=rd();
int w=INF;
if(x<=c[n+1]) w=min(w,ans[kth(x)]);
if(y<=c[n+1]) w=min(w,ans[kth(y)]+1);
printf("%d\n",(w==INF) ? -1 : (n-w+1));
}
}