我想要听你说说 此刻心中所想 有序杂乱 是谁在撒着谎 是谁撒开了网 书写者将造访 此处将被打造成停泊港
test11
厚牛堡(cow)
特判没有 \(0\) 的情况,然后对 \(1\) 的段考虑,考虑长度为 \(l\) 的段包含什么信息。
- 不包含 \(str_1,str_n\),则时间 \(\leq \lfloor\frac{l-1}{2}\rfloor\)。
- 包含 \(str_1(str_n)\),则时间 \(\leq l\)。
贪心希望时间最小,去还原每一段最多有多少奶牛即可。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back
using namespace std;
const int N=300005;
int n, len, Ans;
char str[N];
signed main() {
freopen("cow.in","r",stdin);
freopen("cow.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> (str+1);
for(int l=1, r=1; l<=n; l=r+1, r=l) {
if(str[l]=='0') continue;
while(str[r+1]=='1') ++r;
int val=r-l+1;
if(val%2==0) --val;
if(l==1) val=2*r-1;
if(r==n) val=2*(n-l+1)-1;
if(!len||val<len) len=val;
}
if(!len) { cout << 0 << '\n'; return 0; }
for(int l=1, r=1; l<=n; l=r+1, r=l) {
if(str[l]=='0') continue;
while(str[r+1]=='1') ++r;
if(r-l+1<len) ++Ans;
else Ans+=(r-l+1+len-1)/len;
}
cout << Ans << '\n';
return 0;
}
旅行商(tour)
考虑一个 dp 方程 \(f_u=\min\{f_u,max(f_v-p_{u\to v},w_{u\to v})\}\),为了更新我们期望获得一个美好的顺序。首先进 \(w\) 最大的边一定合法,然后没有贡献,不妨删掉,发现变成递归子问题,期间可以确定删空度数的点的贡献。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(register int i=l; i<=r; ++i)
#define dn(i,r,l) for(register int i=r; i>=l; --i)
#define pb push_back
using namespace std;
const int N=200005, inf=2e9;
int n, m, f[N], in[N], out[N], vis[N];
struct node { int nxt, p, v, id; };
vector<node> F[N], G[N];
struct data{
int i, j, p, v, id;
bool operator<(const data &rhs) const { return v<rhs.v; }
} e[N];
queue<int> q;
signed main() {
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
up(i,1,m) {
cin >> e[i].i >> e[i].j >> e[i].v >> e[i].p;
e[i].id=i, ++in[e[i].j], ++out[e[i].i];
F[e[i].i].pb((node){e[i].j,e[i].p,e[i].v,i});
G[e[i].j].pb((node){e[i].i,e[i].p,e[i].v,i});
}
up(i,1,n) if(!out[i]) q.push(i);
while(q.size()) {
int x=q.front(); q.pop();
for(node o:G[x]) if(!vis[o.id]) {
int y=o.nxt;
--in[x], --out[y], vis[o.id]=1;
if(!out[y]) q.push(y);
}
}
sort(e+1,e+1+m);
up(i,1,n) f[i]=inf;
dn(o,m,1) {
if(vis[e[o].id]) continue;
int i=e[o].i, j=e[o].j;
vis[e[o].id]=1, --in[j], --out[i];
f[i]=min(f[i],e[o].v);
if(!out[i]) {
q.push(i);
while(q.size()) {
int x=q.front(); q.pop();
for(node o:G[x]) if(!vis[o.id]) {
int y=o.nxt;
--in[x], --out[y], vis[o.id]=1;
f[y]=min(f[y],max(o.v,f[x]-o.p));
if(!out[y]) q.push(y);
}
}
}
}
up(i,1,n) {
if(f[i]==inf) f[i]=-1;
cout << f[i] << ' ';
}
return 0;
}
登山hike
因为操作不会让 \(h_j\) 变得比 \(h_i,h_k\) 小,所以结果是固定的,包含所有最大值的极小区间肯定都要改成最大值,然后左右边递归同理。然后考虑怎么操作是最优的,考虑值域是 \(\{sp_1,\dots,sp_m\}\),每次考虑把 \(h_i\leq sp_{u-1}\) 抬高成 \(sp_u\) 肯定是不劣的,因为反正 \(sp_{u-1}/sp_u\) 反正不能向未来贡献,那么现在不妨看看这个过程的最小贡献是什么。特判只用抬 \(0/1\) 个的情况,贪心的我们可以按照 最左最右中间、或最右最左中间的顺序依次操作,这样子中间的都可以获得最好的贡献,对于最左最右的组合也拿不到更好的贡献了。我们模拟这个过程,可以从大到小枚举 \(sp\),用线段树找 rmq,并查集快速找要操作最左最右的位置,我就不赘述了喵。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
using namespace std;
const int N=1000005, inf=1e18, P=1e6+3;
int n, h[N], sp[N], m, ran[N], Ans, tag[N];
int dl[N], dr[N], tr[N<<2];
int sum(int l,int r) {
if((l+r)%2==0) return (l+r)/2*(r-l+1)%P;
return (r-l+1)/2*(l+r)%P;
}
int getl(int x) { return x==dl[x]?x:dl[x]=getl(dl[x]); }
int getr(int x) { return x==dr[x]?x:dr[x]=getr(dr[x]); }
void merl(int i,int j) { i=getl(i), j=getl(j), dl[i]=dl[j]; }
void merr(int i,int j) { i=getr(i), j=getr(j), dr[i]=dr[j]; }
void modify(int x,int v,int p=1,int s=1,int e=n) {
if(s==e) { tr[p]=v; return; }
int mid=(s+e)>>1;
if(x<=mid) modify(x,v,ls(p),s,mid);
if(x>mid) modify(x,v,rs(p),mid+1,e);
tr[p]=min(tr[ls(p)],tr[rs(p)]);
}
int query(int l,int r,int p=1,int s=1,int e=n) {
if(l<=s&&e<=r) return tr[p];
int mid=(s+e)>>1, L=inf, R=inf;
if(l<=mid) L=query(l,r,ls(p),s,mid);
if(r>mid) R=query(l,r,rs(p),mid+1,e);
return min(L,R);
}
signed main() {
// freopen("wa.in","r",stdin);
freopen("hike.in","r",stdin);
freopen("hike.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
up(i,1,4*n) tr[i]=inf;
up(i,1,n) cin >> h[i], sp[++m]=h[i], ran[i]=dl[i]=dr[i]=i;
sort(sp+1,sp+1+m), m=unique(sp+1,sp+1+m)-sp-1;
sort(ran+1,ran+1+n,[](int i,int j){return h[i]>h[j];});
int c=0, L=0, R=0;
dn(u,m,2) {
int l=0, r=0;
while(c<n&&h[ran[c+1]]>=sp[u]) {
int i=ran[++c];
if(!l||i<l) l=i;
if(!r||i>r) r=i;
tag[i]=1, modify(i,h[i]);
if(tag[i-1]) merr(i-1,i), merl(i,i-1);
if(tag[i+1]) merr(i,i+1), merl(i+1,i);
}
if(!L||l<L) L=l;
if(!R||r>R) R=r;
int ll=getr(L)+1, rr=getl(R)-1;
if(R-L+1==c) continue;
if(ll==rr) {
int vl=query(L,ll-1), vr=query(ll+1,R);
(Ans+=(sum(sp[u-1],sp[u]-1)+(vl+vr)%P*(sp[u]-sp[u-1])%P)%P)%=P;
}
else {
(Ans+=(R-L+1-c-2)*(sum(sp[u-1],sp[u]-1)+2*sum(sp[u-1]+1,sp[u])%P)%P)%=P;
int a=query(L,ll-1), b=query(ll+1,R);
int c=query(L,rr-1), d=query(rr+1,R);
if(b<c) {
(Ans+=((a+b)*(sp[u]-sp[u-1])%P+sum(sp[u-1],sp[u]-1))%P)%=P;
(Ans+=((d*(sp[u]-sp[u-1])%P+sum(sp[u-1],sp[u]-1))%P+sum(sp[u-1]+1,sp[u]))%P)%=P;
}
else {
(Ans+=((c+d)*(sp[u]-sp[u-1])%P+sum(sp[u-1],sp[u]-1))%P)%=P;
(Ans+=((a*(sp[u]-sp[u-1])%P+sum(sp[u-1],sp[u]-1))%P+sum(sp[u-1]+1,sp[u]))%P)%=P;
}
}
}
cout << (Ans%P+P)%P << '\n';
return 0;
}

浙公网安备 33010602011771号