qiuzx
2024-03-24 11:22:12
有一个
先进行操作1之后只要让
考虑优化,先将序列翻转这样从前往后扫更好看一些。可以先预处理出序列
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define N 300010
using namespace std;
ll n,q,d,a[N],v[N],s[N],nxt[N],sum[N],sum1[20][N],sum2[20][N],f[20][N];
int main(){
ll i,j;
scanf("%lld%lld",&n,&d);
for(i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
reverse(a,a+n);
for(i=0;i+1<n;i++)
{
__int128 qwq=((__int128)(a[i+1]-a[i]+d-1)+(__int128)LINF*(__int128)d)/(__int128)d;
v[i]=(ll)(qwq-LINF);
s[i+1]=s[i]+v[i];
}
for(i=1;i<n;i++)
{
sum[i]=sum[i-1]+s[i];
}
stack<ll> stk;
stk.push(n);
for(i=n-1;i>=0;i--)
{
while(stk.size()>1)
{
ll x=stk.top();
if(s[x]<s[i])
{
break;
}
stk.pop();
}
nxt[i]=stk.top();
stk.push(i);
}
for(i=0;i<n;i++)
{
sum1[0][i]=s[i]-s[nxt[i]];
sum2[0][i]=(s[i]-s[nxt[i]])*nxt[i];
f[0][i]=nxt[i];
}
f[0][n]=n;
for(i=1;i<20;i++)
{
for(j=0;j<=n;j++)
{
sum1[i][j]=sum1[i-1][j]+sum1[i-1][f[i-1][j]];
sum2[i][j]=sum2[i-1][j]+sum2[i-1][f[i-1][j]];
f[i][j]=f[i-1][f[i-1][j]];
}
}
scanf("%lld",&q);
while(q--)
{
ll l,r,i;
scanf("%lld%lld",&l,&r);
l=n-l,r=n-r;
swap(l,r);
ll ans=0,x=l;
for(i=19;i>=0;i--)
{
if(f[i][x]<=r)
{
ans+=sum1[i][x]*(r+1);
ans-=sum2[i][x];
x=f[i][x];
}
}
ans+=sum[r]-sum[l];
ans-=(r-l)*s[l];
if(a[r]-(s[r]-s[x])*d<0)
{
puts("-1");
}
else
{
printf("%lld\n",ans);
}
}
return 0;
}
有
如果确定了所有点的海拔,怎么连边代价最小呢?首先这个
那么一个自然的想法就是按照海拔从小往大 dp,但 dp 状态怎么设计是一个问题。因此我们需要发掘一些关键的性质。首先需要注意到,如果我们按照海拔一层一层的考虑,则在任意一层考虑完的时候都不可能不存在免费名额。这是因为如果这一层没有点,那么不会占用免费名额,否则这一层的点就是新的免费名额。这也就意味着,如果按照初始海拔逐层考虑,那么对于有点的层,至少会有一个点留下。这是因为反正留下一个点也不会使得后面能用的免费名额减少,且还可能使得后面有更多的连边选择,所以一定是留下更优。且也容易发现一层的点按照
这样一来,如果我们考虑完了前
这样就可以设计出一个 dp 了。记
但这个做法还有一个小问题,就是在离散化海拔之后有可能会存在将点放在两层中间的情况。此时我们先对于高度为
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define N 310
using namespace std;
ll n,d,mnc[N<<1],num[N<<1],f[N][N],g[N][N];
vector<pair<ll,ll> > allv;
vector<ll> allt;
int main(){
ll i,j,k,p,x,y;
cin>>n>>d;
memset(mnc,63,sizeof(mnc));
for(i=0;i<n;i++)
{
cin>>x>>y;
x++;
allv.push_back(make_pair(x,y));
allt.push_back(x);
allt.push_back(x+1);
}
allt.push_back(0);
sort(allt.begin(),allt.end());
allt.erase(unique(allt.begin(),allt.end()),allt.end());
for(i=0;i<allv.size();i++)
{
x=lower_bound(allt.begin(),allt.end(),allv[i].F)-allt.begin(),y=allv[i].S;
mnc[x]=min(mnc[x],y);
num[x]++;
}
for(i=1;i<allt.size();i++)
{
mnc[i]=min(mnc[i],mnc[i-1]);
}
memset(f,63,sizeof(f));
f[1][0]=0;
for(i=1;i<allt.size();i++)
{
for(j=0;j<=n;j++)
{
for(k=0;k<=n;k++)
{
g[j][k]=LINF;
}
}
for(j=0;j<=n;j++)
{
for(k=0;k<=n;k++)
{
if(f[j][k]>=LINF)
{
continue;
}
if(j>=k+num[i])
{
g[j][0]=min(g[j][0],f[j][k]);
}
else
{
ll lim=(i==allt.size()-1?INF:allt[i+1]-allt[i]);
if(mnc[i-1]<LINF)
{
g[k+num[i]][0]=min(g[k+num[i]][0],f[j][k]+(k+num[i]-j)*mnc[i-1]);
}
if(lim==1)
{
for(p=j;p<=(mnc[i-1]>=LINF?j:k+num[i]);p++)
{
g[p][k+num[i]-p]=min(g[p][k+num[i]-p],f[j][k]+(p-j)*mnc[i-1]+(k+num[i]-p)*d);
}
}
else
{
for(p=j;p<=(mnc[i-1]>=LINF?j:k+num[i]);p++)
{
ll v=k+num[i]-p;
if(p*(lim-1)<=v)
{
ll cost=f[j][k]+(p-j)*mnc[i-1];
cost+=p*d*(lim*(lim-1)/2);
cost+=(v-p*(lim-1))*lim*d;
g[p][v-p*(lim-1)]=min(g[p][v-p*(lim-1)],cost);
}
else
{
ll cost=f[j][k]+(p-j)*mnc[i-1],mx=v/p;
cost+=p*d*(mx*(mx+1)/2);
cost+=(v%p)*d*(mx+1);
g[p][0]=min(g[p][0],cost);
}
}
}
}
}
}
for(j=0;j<=n;j++)
{
for(k=0;k<=n;k++)
{
f[j][k]=g[j][k];
}
}
}
ll ans=LINF;
for(i=0;i<=n;i++)
{
ans=min(ans,f[i][0]);
}
cout<<ans<<'\n';
return 0;
}
一张
我们先确定一个从
先不管
这种情况看起来是走到最近的一个满足这个条件的终止节点最优,但事实上并非如此。注意到前一种情况中我们走到最近的终止节点,那么路径上一定不存在终止节点,所以一步可以走完。但这种情况中有可能路径上会存在不合法的终止节点,但我们会在那里被强制停下。但假设某一条路径先走
如果
因此对于一个棋子,它对答案的贡献是两种情况的最小值:
然而这个看起来没法优化了。但注意到
那么
平衡一下复杂度即可,可以做到
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define N 50010
using namespace std;
ll n,m,d,tp[N],plc[N],v1[N],v2[N],dis[N],dp[N][550],f[2][N<<1],ans[N];
string s;
vector<ll> vt[N];
void bfs1()
{
ll i;
queue<ll> qu;
for(i=0;i<n;i++)
{
dis[i]=LINF;
if(tp[i]!=-1)
{
dis[i]=0;
qu.push(i);
}
}
while(!qu.empty())
{
ll x=qu.front();
qu.pop();
for(i=0;i<vt[x].size();i++)
{
if(dis[vt[x][i]]>dis[x]+1)
{
dis[vt[x][i]]=dis[x]+1;
qu.push(vt[x][i]);
}
}
}
for(i=0;i<n;i++)
{
v1[i]=max(tp[i]>=0?0ll:-1ll,dis[i]-2);
}
return;
}
void bfs2()
{
ll i;
deque<ll> qu;
vector<bool> vis(n,false);
for(i=0;i<n;i++)
{
dis[i]=LINF;
if(tp[i]==1)
{
dis[i]=0;
qu.push_back(i);
}
}
while(!qu.empty())
{
ll x=qu.front();
qu.pop_front();
if(vis[x])
{
continue;
}
vis[x]=true;
for(i=0;i<vt[x].size();i++)
{
if(dis[vt[x][i]]>dis[x]+1-(tp[x]>=0))
{
dis[vt[x][i]]=dis[x]+1-(tp[x]>=0);
if(tp[x]>=0)
{
qu.push_front(vt[x][i]);
}
else
{
qu.push_back(vt[x][i]);
}
}
}
}
for(i=0;i<n;i++)
{
v2[i]=dis[i];
}
return;
}
void solve(ll pre,ll k)
{
ll i;
for(i=0;i<n;i++)
{
dp[i][0]=dp[i][1]=LINF;
}
dp[plc[0]][0]=0;
priority_queue<pair<ll,pair<ll,ll> > > pq;
pq.push(make_pair(0,make_pair(plc[0],0)));
while(!pq.empty())
{
ll x=pq.top().S.F,y=pq.top().S.S,w=-pq.top().F;
pq.pop();
for(i=0;i<vt[x].size();i++)
{
ll cost=w+(x!=plc[0]&&tp[x]>=0?k:0)+1,t=(x!=plc[0]&&tp[x]>=0);
if(dp[vt[x][i]][y|t]>cost)
{
dp[vt[x][i]][y|t]=cost;
pq.push(make_pair(-cost,make_pair(vt[x][i],y|t)));
}
}
}
for(i=0;i<n;i++)
{
ans[i]=min(ans[i],(k==LINF?dp[i][0]:dp[i][1])+pre);
}
return;
}
ll mnd[N],wei[N];
void bfs3()
{
ll i;
deque<ll> qu;
vector<bool> vis(n,false);
for(i=0;i<n;i++)
{
mnd[i]=INF;
}
qu.push_back(plc[0]);
mnd[plc[0]]=0;
while(!qu.empty())
{
ll x=qu.front();
qu.pop_front();
if(vis[x])
{
continue;
}
vis[x]=true;
for(i=0;i<vt[x].size();i++)
{
ll w=(x!=plc[0]&&tp[x]>=0);
if(mnd[vt[x][i]]>mnd[x]+w)
{
mnd[vt[x][i]]=mnd[x]+w;
if(w==0)
{
qu.push_front(vt[x][i]);
}
else
{
qu.push_back(vt[x][i]);
}
}
}
}
return;
}
ll c1[N],c2[N];
void solve0()
{
ll i,j;
for(i=1;i<d;i++)
{
ll lim=min(n,max(0ll,v2[plc[i]]-v1[plc[i]]));
c1[1]+=2,c1[lim+1]-=2;
c2[1]+=v1[plc[i]],c2[lim+1]-=v1[plc[i]];
c1[lim+1]++;
c2[lim+1]+=v2[plc[i]];
}
c1[0]=c2[0]=0;
for(i=1;i<N;i++)
{
c1[i]+=c1[i-1];
c2[i]+=c2[i-1];
}
bfs3();
memset(dp,63,sizeof(dp));
queue<pair<ll,ll> > qu;
dp[plc[0]][0]=0;
qu.push(make_pair(plc[0],0));
while(!qu.empty())
{
ll x=qu.front().F,y=qu.front().S+mnd[x];
qu.pop();
for(i=0;i<vt[x].size();i++)
{
ll t=(x!=plc[0]&&tp[x]>=0);
if(dp[vt[x][i]][y+t-mnd[vt[x][i]]]>dp[x][y-mnd[x]]+1&&y+t-mnd[vt[x][i]]<550)
{
dp[vt[x][i]][y+t-mnd[vt[x][i]]]=dp[x][y-mnd[x]]+1;
qu.push(make_pair(vt[x][i],y+t-mnd[vt[x][i]]));
}
}
}
for(i=0;i<n;i++)
{
ans[i]=LINF;
for(j=0;j<550&&j+mnd[i]<N;j++)
{
if(dp[i][j]<LINF)
{
ans[i]=min(ans[i],dp[i][j]+c1[j+mnd[i]]*(j+mnd[i])+c2[j+mnd[i]]);
}
}
cout<<ans[i]<<'\n';
}
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
ll i,j,x,y;
cin>>n>>m>>d;
for(i=0;i<m;i++)
{
cin>>x>>y;
x--,y--;
vt[x].push_back(y);
vt[y].push_back(x);
}
cin>>s;
for(i=0;i<n;i++)
{
if(s[i]=='0')
{
tp[i]=-1;
}
else
{
tp[i]=0;
for(j=0;j<vt[i].size();j++)
{
if(s[vt[i][j]]=='1')
{
tp[i]=1;
break;
}
}
}
}
for(i=0;i<d;i++)
{
cin>>plc[i];
plc[i]--;
}
bfs1();
bfs2();
if(d>100)
{
solve0();
return 0;
}
memset(f,63,sizeof(f));
f[0][0]=0;
for(i=1;i<d;i++)
{
ll u=(i&1)^1,v=i&1;
for(j=0;j<=i*2;j++)
{
f[v][j]=LINF;
}
for(j=0;j<=i*2;j++)
{
f[v][j+2]=min(f[v][j+2],f[u][j]+v1[plc[i]]);
f[v][j+1]=min(f[v][j+1],f[u][j]+v2[plc[i]]);
}
}
memset(ans,63,sizeof(ans));
for(i=0;i<=d*2;i++)
{
if(f[(d-1)&1][i]<LINF)
{
solve(f[(d-1)&1][i],i);
}
}
solve(0,LINF);
for(i=0;i<n;i++)
{
cout<<ans[i]<<'\n';
}
return 0;
}
给定一个长度为
假如确定了哪些和
二分答案,则只需要检查是否可以让每一对元素之差的绝对值都不超过这个值即可。先将
考虑在移动左端点的时候一个数的排名怎么变化。容易发现每次会删掉一个比它小的点,再加入一个右边的点。而右边加入的点越来越小,所以前面一段这个点的排名会一直减小
这样对每个点可以求出两个区间,分别表示左端点在其中的时候这个点可以和
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define N 300010
using namespace std;
ll n,a[N<<1],b[N],c[N],idx[N<<1][2];
pair<ll,ll> rgl[N<<1],rgr[N<<1];
void update(ll tp,ll lim)
{
ll i,j,l,r;
for(i=0,j=n*2-1,l=r=0;i<n;i++)
{
while(l<n&&b[l]<a[i]-lim)
{
l++;
}
while(r<n&&b[r]<=a[i]+lim)
{
r++;
}
while(j>=n&&a[j]<a[i])
{
j--;
}
//i,i-1,...,i-(j-n+1),i-(j-n+1),...
ll lo=max(l,i-(j-n+1)),hi=min(r-1,i);
rgl[idx[i][tp]].F=i-hi;
rgl[idx[i][tp]].S=(lo==i-(j-n+1)?i:i-lo);
}
for(i=0,j=n*2-1,l=r=0;i<n;i++)
{
while(l<n&&c[l]<a[i]-lim)
{
l++;
}
while(r<n&&c[r]<=a[i]+lim)
{
r++;
}
while(j>=n&&a[j]<a[i])
{
j--;
}
//i,i+1,...,i+(n*2-j-1),i+(n*2-j-1),...
ll lo=max(l,i),hi=min(r-1,i+n*2-j-1);
if(lo>hi)
{
rgr[idx[i][tp]].F=n;
}
else
{
rgr[idx[i][tp]].F=max(i+1,hi==i+n*2-j-1?i+1:n-(hi-i));
}
rgr[idx[i][tp]].S=min(n-1,n-(lo-i));
}
return;
}
ll d[N];
bool check(ll lim)
{
ll i;
update(0,lim*INF+INF/2);
vector<ll> tmp(n*2);
for(i=0;i<n*2;i++)
{
tmp[i]=a[i];
}
for(i=0;i<n*2;i++)
{
a[i]=-tmp[(i+n)%(n*2)];
}
for(i=0;i<n;i++)
{
b[i]=-b[i];
c[i]=-c[i];
}
reverse(b,b+n);
reverse(c,c+n);
swap(b,c);
update(1,lim*INF+INF/2);
swap(b,c);
reverse(b,b+n);
reverse(c,c+n);
for(i=0;i<n*2;i++)
{
a[i]=tmp[i];
}
for(i=0;i<n;i++)
{
b[i]=-b[i];
c[i]=-c[i];
}
for(i=0;i<n;i++)
{
d[i]=0;
}
for(i=0;i<n*2;i++)
{
if(rgl[i].F<=rgl[i].S)
{
d[rgl[i].F]++;
d[rgl[i].S+1]--;
}
if(rgr[i].F<=rgr[i].S)
{
d[rgr[i].F]++;
d[rgr[i].S+1]--;
}
}
for(i=0;i<n;i++)
{
d[i+1]+=d[i];
if(d[i]==n*2)
{
return true;
}
}
return false;
}
bool hahaha(ll lim)
{
if(check(lim))
{
return true;
}
swap(b,c);
bool ret=check(lim);
swap(b,c);
return ret;
}
int main(){
ll i;
scanf("%lld",&n);
for(i=0;i<n*2;i++)
{
idx[i][0]=i;
idx[i][1]=(i+n)%(n*2);
scanf("%lld",&a[i]);
a[i]=a[i]*INF+i;
}
for(i=0;i<n;i++)
{
scanf("%lld",&b[i]);
b[i]*=INF;
}
for(i=0;i<n;i++)
{
scanf("%lld",&c[i]);
c[i]*=INF;
}
sort(b,b+n);
sort(c,c+n);
ll l=0,r=INF;
while(l<r)
{
ll mid=(l+r)>>1;
if(hahaha(mid))
{
r=mid;
}
else
{
l=mid+1;
}
}
printf("%lld\n",l);
return 0;
}
有
考虑一次询问怎么回答。注意到这两维是相对独立的,即它们不会交叉取
先考虑一种比较简单的情形,如果上下各只有一个
下面考虑较为一般的情形。首先如果有多个
下面考虑两个
当然还有一个小问题,即我们还没有说明不可能出现仅考虑左边无法变成某个状态,但加入右边的数可以变成对应状态的情况。同样不妨假设当前是
还有一个问题是多个
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define N 200010
using namespace std;
ll n,m,a[N],b[N],tp[N][2];
bool pre[N][2][2],suf[N][2][2],okl0[N],okl1[N],okr0[N],okr1[N];
vector<ll> ans;
bool calc(ll l,ll r)
{
if(l==-1||r==-1||l>=r)
{
return false;
}
ll i;
bool hv0=false,hv1=false;
for(i=l+1;i<r;i++)
{
if(tp[i][0]>=0&&tp[i][1]<=0)
{
hv1=true;
}
if(tp[i][0]<=0&&tp[i][1]>=0)
{
hv0=true;
}
}
if(okl0[l]&&okr0[r])
{
return true;
}
if(okl1[l]&&okr1[r])
{
return true;
}
if(okl0[l]&&okr1[r]&&hv0)
{
return true;
}
if(okl1[l]&&okr0[r]&&hv1)
{
return true;
}
return false;
}
bool check(ll x,ll y)
{
ll i,j;
for(i=0;i<n;i++)
{
tp[i][0]=(a[i]==x?0:(a[i]>x?1:-1));
tp[i][1]=(b[i]==y?0:(b[i]>y?1:-1));
}
memset(pre,false,sizeof(pre));
memset(suf,false,sizeof(suf));
for(i=0;i<n;i++)
{
if(tp[i][0]>=0&&tp[i][1]>=0)
{
pre[i][1][1]=true;
}
if(tp[i][0]>=0&&tp[i][1]<=0)
{
pre[i][1][0]=true;
}
if(tp[i][0]<=0&&tp[i][1]>=0)
{
pre[i][0][1]=true;
}
if(tp[i][0]<=0&&tp[i][1]<=0)
{
pre[i][0][0]=true;
}
pre[i+1][0][0]=pre[i][0][0];
pre[i+1][0][1]=pre[i][0][1];
pre[i+1][1][0]=pre[i][1][0];
pre[i+1][1][1]=pre[i][1][1];
}
for(i=n-1;i>=0;i--)
{
suf[i][0][0]=suf[i+1][0][0];
suf[i][0][1]=suf[i+1][0][1];
suf[i][1][0]=suf[i+1][1][0];
suf[i][1][1]=suf[i+1][1][1];
if(tp[i][0]>=0&&tp[i][1]>=0)
{
suf[i][1][1]=true;
}
if(tp[i][0]>=0&&tp[i][1]<=0)
{
suf[i][1][0]=true;
}
if(tp[i][0]<=0&&tp[i][1]>=0)
{
suf[i][0][1]=true;
}
if(tp[i][0]<=0&&tp[i][1]<=0)
{
suf[i][0][0]=true;
}
}
for(i=0;i<n;i++)
{
if(tp[i][0]==0&&tp[i][1]==0)
{
if(i==0||((pre[i-1][1][0]||pre[i-1][1][1])&&(pre[i-1][0][1]||pre[i-1][1][1]))||((pre[i-1][0][0]||pre[i-1][0][1])&&(pre[i-1][0][0]||pre[i-1][1][0])))
{
if(i==n-1||((suf[i+1][1][0]||suf[i+1][1][1])&&(suf[i+1][0][1]||suf[i+1][1][1]))||((suf[i+1][0][0]||suf[i+1][0][1])&&(suf[i+1][0][0]||suf[i+1][1][0])))
{
return true;
}
}
}
}
ll lst0=-1,lst1=-1;
for(i=0;i<n;i++)
{
if(tp[i][0]==0)
{
okl1[i]=okl0[i]=false;
if(tp[i][1]>=0)
{
if(i==0||pre[i-1][0][0]||pre[i-1][0][1]||pre[i-1][1][1])
{
okl1[i]=true;
}
j=lst0;
if(j>=0&&(j==0||pre[j-1][0][0]||pre[j-1][1][0]||pre[j-1][1][1]))
{
okl0[i]=true;
}
}
if(tp[i][1]<=0)
{
if(i==0||pre[i-1][0][0]||pre[i-1][1][0]||pre[i-1][1][1])
{
okl0[i]=true;
}
j=lst1;
if(j>=0&&(j==0||pre[j-1][0][0]||pre[j-1][0][1]||pre[j-1][1][1]))
{
okl1[i]=true;
}
}
}
if(tp[i][0]>=0&&tp[i][1]<=0)
{
lst0=i;
}
if(tp[i][0]<=0&&tp[i][1]>=0)
{
lst1=i;
}
}
lst0=lst1=n;
for(i=n-1;i>=0;i--)
{
if(tp[i][1]==0)
{
okr1[i]=okr0[i]=false;
if(tp[i][0]>=0)
{
if(i==n-1||suf[i+1][0][0]||suf[i+1][1][0]||suf[i+1][1][1])
{
okr1[i]=true;
}
j=lst1;
if(j<n&&(j==n-1||suf[j+1][0][0]||suf[j+1][0][1]||suf[j+1][1][1]))
{
okr0[i]=true;
}
}
if(tp[i][0]<=0)
{
if(i==n-1||suf[i+1][0][0]||suf[i+1][0][1]||suf[i+1][1][1])
{
okr0[i]=true;
}
j=lst0;
if(j<n&&(j==n-1||suf[j+1][0][0]||suf[j+1][1][0]||suf[j+1][1][1]))
{
okr1[i]=true;
}
}
}
if(tp[i][0]>=0&&tp[i][1]<=0)
{
lst0=i;
}
if(tp[i][0]<=0&&tp[i][1]>=0)
{
lst1=i;
}
}
ll mn0=-1,mn1=-1;
for(i=0;i<n;i++)
{
if(tp[i][0]==0&&okl0[i])
{
mn0=i;
break;
}
}
for(i=0;i<n;i++)
{
if(tp[i][0]==0&&okl1[i])
{
mn1=i;
break;
}
}
ll mx0=-1,mx1=-1;
for(i=n-1;i>=0;i--)
{
if(tp[i][1]==0&&okr0[i])
{
mx0=i;
break;
}
}
for(i=n-1;i>=0;i--)
{
if(tp[i][1]==0&&okr1[i])
{
mx1=i;
break;
}
}
if(calc(mn0,mx0))
{
return true;
}
if(calc(mn1,mx0))
{
return true;
}
if(calc(mn0,mx1))
{
return true;
}
if(calc(mn1,mx1))
{
return true;
}
return false;
}
int main(){
ll i,x,y;
scanf("%lld%lld",&n,&m);
for(i=0;i<n;i++)
{
scanf("%lld%lld",&a[i],&b[i]);
}
for(i=0;i<m;i++)
{
scanf("%lld%lld",&x,&y);
if(check(x,y))
{
ans.push_back(i);
}
else
{
swap(x,y),swap(a,b);
if(check(x,y))
{
ans.push_back(i);
}
swap(x,y),swap(a,b);
}
}
for(i=0;i<ans.size();i++)
{
printf("%lld ",ans[i]+1);
}
puts("");
return 0;
}
目前只有 71 分的,满分先咕着。
给定一棵
对于固定局面的答案,可以用任意选择一个
先考虑维护子树外部分的答案。若记
再考虑维护子树中的答案,如果仿照上面一种方式来处理,问题在于此时
对于重边来说,此时一次修改会将一条链上的
对于轻边来说,我们在每个点上维护以它为父亲的所有轻边的
#include "joitour.h"
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define N 200010
using namespace std;
struct Tag{
ll va,vb;
Tag(){va=vb=0;}
Tag(ll _a,ll _b){va=_a,vb=_b;}
Tag operator + (const Tag &x)const{
return Tag(va+x.va,vb+x.vb);
}
};
struct Node{
ll ans,va,vb,vc,vac,vbc,len;
Node(){ans=va=vb=vc=vac=vbc=len=0;}
Node(ll _s,ll _l,ll _a,ll _b,ll _c,ll _ac,ll _bc){ans=_s,len=_l,va=_a,vb=_b,vc=_c,vac=_ac,vbc=_bc;}
Node operator + (const Node &x)const{
return Node(ans+x.ans,len+x.len,va+x.va,vb+x.vb,vc+x.vc,vac+x.vac,vbc+x.vbc);
}
Node operator + (const Tag &x)const{
return Node(ans+x.va*vbc+x.vb*vac+x.va*x.vb*vc,len,va+x.va*len,vb+x.vb*len,vc,vac+x.va*vc,vbc+x.vb*vc);
}
};
struct SegT{
ll lo[N<<2],hi[N<<2],pre[N][3];
Node val[N<<2];
Tag pd[N<<2];
void build(ll x,ll l,ll r)
{
lo[x]=l,hi[x]=r;
if(l==r)
{
val[x]=Node(pre[l][0]*pre[l][1]*pre[l][2],1,pre[l][0],pre[l][1],pre[l][2],pre[l][0]*pre[l][2],pre[l][1]*pre[l][2]);
return;
}
ll mid=(l+r)>>1,a=x<<1;
build(a,l,mid);
build(a|1,mid+1,r);
val[x]=val[a]+val[a|1];
return;
}
void pushdown(ll x)
{
ll a=x<<1;
val[a]=val[a]+pd[x];
pd[a]=pd[a]+pd[x];
val[a|1]=val[a|1]+pd[x];
pd[a|1]=pd[a|1]+pd[x];
pd[x]=Tag(0,0);
return;
}
void update(ll x,ll l,ll r,Tag v)
{
ll tl=lo[x],tr=hi[x];
if(l<=tl&&tr<=r)
{
val[x]=val[x]+v;
pd[x]=pd[x]+v;
return;
}
pushdown(x);
ll mid=(tl+tr)>>1,a=x<<1;
if(mid>=l)
{
update(a,l,r,v);
}
if(mid<r)
{
update(a|1,l,r,v);
}
val[x]=val[a]+val[a|1];
return;
}
void modify(ll x,ll l,ll v)
{
ll tl=lo[x],tr=hi[x];
if(tl==tr)
{
ll va=val[x].va,vb=val[x].vb,vc=v;
val[x]=Node(va*vb*vc,1,va,vb,vc,va*vc,vb*vc);
return;
}
pushdown(x);
ll mid=(tl+tr)>>1,a=x<<1;
if(mid>=l)
{
modify(a,l,v);
}
else
{
modify(a|1,l,v);
}
val[x]=val[a]+val[a|1];
return;
}
}segt1,segt2;
ll n,q,fa[N],col[N],sz[N][3],tothv[3],totsm=0,valsm[N];
ll num[N],hson[N],tp[N],din[N],dout[N],dcnt=0;
vector<ll> vt[N];
void predfs(ll x,ll lst)
{
ll i;
sz[x][0]=sz[x][1]=sz[x][2]=0;
sz[x][col[x]]=1;
num[x]=1;
fa[x]=lst;
hson[x]=-1;
for(i=0;i<vt[x].size();i++)
{
if(vt[x][i]!=lst)
{
predfs(vt[x][i],x);
num[x]+=num[vt[x][i]];
sz[x][0]+=sz[vt[x][i]][0];
sz[x][1]+=sz[vt[x][i]][1];
sz[x][2]+=sz[vt[x][i]][2];
if(hson[x]==-1||num[hson[x]]<num[vt[x][i]])
{
hson[x]=vt[x][i];
}
}
}
return;
}
void dfs(ll x,ll lst,bool ist=true)
{
ll i;
tp[x]=ist?x:tp[lst];
din[x]=++dcnt;
if(hson[x]!=-1)
{
dfs(hson[x],x,false);
}
for(i=0;i<vt[x].size();i++)
{
if(vt[x][i]!=lst&&vt[x][i]!=hson[x])
{
dfs(vt[x][i],x);
}
}
dout[x]=dcnt;
return;
}
void init(int _n,vector<int> _f,vector<int> _u,vector<int> _v,int _q)
{
ll i;
n=_n,q=_q;
tothv[0]=tothv[1]=tothv[2]=0;
for(i=0;i<n;i++)
{
col[i]=_f[i];
tothv[col[i]]++;
}
for(i=0;i<n-1;i++)
{
vt[_u[i]].push_back(_v[i]);
vt[_v[i]].push_back(_u[i]);
}
predfs(0,-1);
dfs(0,-1);
for(i=1;i<=n;i++)
{
segt1.pre[i][0]=segt1.pre[i][1]=segt1.pre[i][2]=0;
segt2.pre[i][0]=segt2.pre[i][1]=segt2.pre[i][2]=0;
}
for(i=1;i<n;i++)
{
if(i==hson[fa[i]])
{
segt1.pre[din[fa[i]]][0]=sz[i][0];
segt1.pre[din[fa[i]]][1]=sz[i][2];
segt1.pre[din[fa[i]]][2]=(col[fa[i]]==1);
}
else
{
valsm[fa[i]]+=sz[i][0]*sz[i][2];
if(col[fa[i]]==1)
{
totsm+=sz[i][0]*sz[i][2];
}
}
segt2.pre[din[i]][0]=tothv[0]-sz[i][0];
segt2.pre[din[i]][1]=tothv[2]-sz[i][2];
segt2.pre[din[i]][2]=(col[i]==1);
}
segt1.build(1,1,n);
segt2.build(1,1,n);
return;
}
void upd(ll x,ll y,ll c)
{
ll i;
tothv[col[x]]+=c;
if(y==1)
{
totsm+=valsm[x]*c;
segt1.modify(1,din[x],max(0ll,c));
segt2.modify(1,din[x],max(0ll,c));
}
else
{
vector<pair<ll,ll> > seq;
while(x>=0)
{
seq.push_back(make_pair(din[tp[x]],din[x]));
if(din[tp[x]]<din[x])
{
segt1.update(1,din[tp[x]],din[x]-1,Tag(y==0?c:0,y==0?0:c));
}
x=tp[x];
if(x>0)
{
if(col[fa[x]]==1)
{
totsm-=valsm[fa[x]];
}
valsm[fa[x]]-=sz[x][0]*sz[x][2];
sz[x][y]+=c;
valsm[fa[x]]+=sz[x][0]*sz[x][2];
if(col[fa[x]]==1)
{
totsm+=valsm[fa[x]];
}
}
x=fa[x];
}
sort(seq.begin(),seq.end());
seq.push_back(make_pair(n+1,INF));
for(i=1;i<seq.size();i++)
{
if(seq[i-1].S+1<=seq[i].F-1)
{
segt2.update(1,seq[i-1].S+1,seq[i].F-1,Tag(y==0?c:0,y==0?0:c));
}
}
}
return;
}
void change(int _x,int _y)
{
ll x=_x,y=_y;
if(col[x]==y)
{
return;
}
upd(x,col[x],-1);
col[x]=y;
upd(x,col[x],1);
return;
}
ll num_tours()
{
ll ans=tothv[0]*tothv[1]*tothv[2];
ans-=totsm;
ans-=segt1.val[1].ans;
ans-=segt2.val[1].ans;
return ans;
}
有一个无穷大的台阶,一个人初始在
容易求出
下面考虑最大步数怎么算。此时比较麻烦的一点在于一段中的最大步数是不一样的。但其实这个的规律性还是比较明显。对于第一个区间而言,一定是每
不过直接这样写只做所有交非空的转移就过了,那么这是为什么呢?其实原因就是两个大段之间转移至多会产生
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define N 200010
using namespace std;
ll n,q,D,A,B,mnp[N],f[N];
vector<pair<pair<ll,ll>,ll> > g[N];
pair<ll,ll> badp[N];
vector<pair<ll,ll> > seq;
pair<ll,ll> ask(ll p,ll x)
{
pair<pair<ll,ll>,ll> fd=make_pair(make_pair(x+1,-INF),-INF);
ll i=lower_bound(g[p].begin(),g[p].end(),fd)-g[p].begin()-1;
if(i<0)
{
return make_pair(i,-LINF);
}
ll l=g[p][i].F.F,r=g[p][i].F.S,w=g[p][i].S;
if(l<=x&&x<=r)
{
return make_pair(i,w);
}
return make_pair(i,w+(x-r-1)/D+1);
}
int main(){
ll i,j;
scanf("%lld%lld%lld%lld%lld",&n,&q,&D,&A,&B);
for(i=0;i<n;i++)
{
scanf("%lld%lld",&badp[i].F,&badp[i].S);
}
seq.push_back(make_pair(0,badp[0].F-1));
for(i=1;i<n;i++)
{
seq.push_back(make_pair(badp[i-1].S+1,badp[i].F-1));
}
seq.push_back(make_pair(badp[n-1].S+1,LINF));
for(i=0;i<seq.size();i++)
{
mnp[i]=LINF+5;
}
mnp[0]=0;
for(i=0;i<seq.size();i++)
{
ll l=mnp[i]+D,r=seq[i].S+D;
pair<ll,ll> fd=make_pair(l+1,-INF);
ll p=lower_bound(seq.begin(),seq.end(),fd)-seq.begin()-1;
p=max(p,i+1);
while(p<seq.size()&&seq[p].F<=r)
{
ll lo=max(l,seq[p].F),hi=min(r,seq[p].S);
if(lo<=hi)
{
mnp[p]=min(mnp[p],lo);
}
p++;
}
}
vector<pair<ll,ll> > rgs;
for(i=0;i<seq.size();i++)
{
if(mnp[i]<=seq[i].S)
{
rgs.push_back(make_pair(mnp[i],seq[i].S));
}
}
sort(rgs.begin(),rgs.end());
memset(f,63,sizeof(f));
f[0]=0;
g[0].push_back(make_pair(make_pair(0,min(D-1,rgs[0].S)),0));
for(i=0;i<rgs.size();i++)
{
ll l=rgs[i].F+D,r=rgs[i].S+D;
pair<ll,ll> fd=make_pair(l+1,-INF);
ll p=lower_bound(rgs.begin(),rgs.end(),fd)-rgs.begin()-1;
p=max(p,i+1);
while(p<rgs.size()&&rgs[p].F<=r)
{
ll lo=max(l,rgs[p].F),hi=min(r,rgs[p].S);
if(lo<=hi)
{
f[p]=min(f[p],f[i]+1);
}
p++;
}
for(j=0;j<g[i].size();j++)
{
l=g[i][j].F.F+D,r=(j==g[i].size()-1?rgs[i].S:g[i][j+1].F.F-1)+D;
fd=make_pair(l+1,-INF);
p=lower_bound(rgs.begin(),rgs.end(),fd)-rgs.begin()-1;
p=max(p,i+1);
while(p<rgs.size()&&rgs[p].F<=r)
{
ll lo=max(l,rgs[p].F),hi=min(r,rgs[p].S);
if(lo<=hi)
{
ll tl=lo-D,tr=hi-D,len,w;
if(ask(i,tr)==ask(i,tl))
{
len=D;
w=ask(i,tl).S;
}
else if(tl<=g[i][j].F.S)
{
len=g[i][j].F.S-tl+1;
w=g[i][j].S;
}
else
{
len=D-((tl-g[i][j].F.S-1)%D);
w=g[i][j].S+(tl-g[i][j].F.S-1)/D+1;
}
pair<ll,ll> cur=ask(p,lo);
if(cur.S<w+1)
{
if(cur.F>=0&&g[p][cur.F].F.S>=lo)
{
g[p][cur.F].F.S=lo-1;
}
g[p].push_back(make_pair(make_pair(lo,min(lo+len-1,rgs[p].S)),w+1));
}
else if(cur.S==w+1)
{
ll lft;
if(g[p][cur.F].F.F<=lo&&lo<=g[p][cur.F].F.S)
{
lft=g[p][cur.F].F.S-lo+1;
}
else
{
lft=D-((lo-g[p][cur.F].F.S-1)%D);
}
if(len<lft)
{
if(cur.F>=0&&g[p][cur.F].F.S>=lo)
{
g[p][cur.F].F.S=lo-1;
}
g[p].push_back(make_pair(make_pair(lo,min(lo+len-1,rgs[p].S)),w+1));
}
}
}
p++;
}
}
}
while(q--)
{
ll x;
scanf("%lld",&x);
pair<ll,ll> fd=make_pair(x+1,-INF);
ll p=lower_bound(rgs.begin(),rgs.end(),fd)-rgs.begin()-1;
if(p>=0&&rgs[p].F<=x&&rgs[p].S>=x)
{
ll ans=(x-f[p]*D)*A+f[p]*B;
ll y=ask(p,x).S;
ans=min(ans,(x-y*D)*A+y*B);
printf("%lld\n",ans);
}
else
{
puts("-1");
}
}
return 0;
}
有
显然若
若从
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define N 100010
using namespace std;
ll n,q,T,cnt=0,fa[N],par[N],dep[N],res[N][400],ans[300010];
vector<ll> idx[N],curhv[N];
vector<pair<ll,ll> > eds[N],vt[N],qry[N];
void dfs(ll x)
{
ll i;
for(i=0;i<vt[x].size();i++)
{
dep[vt[x][i].F]=dep[x]+vt[x][i].S;
dfs(vt[x][i].F);
}
return;
}
bool cmp(ll x,ll y)
{
return curhv[x].size()>curhv[y].size();
}
int main(){
ll i,j,k,x;
scanf("%lld%lld",&n,&T);
for(i=0;i+1<n;i++)
{
scanf("%lld",&x);
eds[i].resize(x);
for(j=0;j<x;j++)
{
scanf("%lld%lld",&eds[i][j].F,&eds[i][j].S);
}
sort(eds[i].begin(),eds[i].end());
vector<pair<ll,ll> > nw;
for(j=0;j<x;j++)
{
while(!nw.empty())
{
if(nw.back().S<eds[i][j].S)
{
break;
}
nw.pop_back();
}
if((!nw.empty())&&eds[i][j].F<=nw.back().F)
{
continue;
}
nw.push_back(eds[i][j]);
}
eds[i]=nw;
for(j=0;j<eds[i].size();j++)
{
idx[i].push_back(cnt++);
}
}
for(i=0;i<n-1;i++)
{
for(j=x=0;j<eds[i].size();j++)
{
while(x<eds[i+1].size()&&eds[i+1][x].F<eds[i][j].S)
{
x++;
}
if(x>=eds[i+1].size())
{
if(eds[i+1].empty())
{
fa[idx[i][j]]=cnt;
par[idx[i][j]]=0;
vt[cnt].push_back(make_pair(idx[i][j],0));
}
else
{
fa[idx[i][j]]=idx[i+1][0];
par[idx[i][j]]=eds[i+1][0].S+T-eds[i][j].S;
vt[idx[i+1][0]].push_back(make_pair(idx[i][j],eds[i+1][0].S+T-eds[i][j].S));
}
}
else
{
fa[idx[i][j]]=idx[i+1][x];
par[idx[i][j]]=eds[i+1][x].S-eds[i][j].S;
vt[idx[i+1][x]].push_back(make_pair(idx[i][j],eds[i+1][x].S-eds[i][j].S));
}
}
}
dfs(cnt);
memset(res,63,sizeof(res));
for(i=0;i<n;i++)
{
for(j=0;j<eds[i].size();j++)
{
ll cur=eds[i][j].S-eds[i][j].F,id=idx[i][j];
for(x=i+1;x<i+400&&x<n;x++)
{
res[i][x-i]=min(res[i][x-i],cur);
cur+=par[id];
id=fa[id];
}
}
}
scanf("%lld",&q);
for(i=0;i<q;i++)
{
ll l,r;
scanf("%lld%lld",&l,&r);
l--,r--;
if(r-l<380)
{
ans[i]=res[l][r-l];
}
else
{
ans[i]=LINF;
qry[r-1].push_back(make_pair(l,i));
}
}
for(i=0;i<n;i++)
{
for(j=0;j<eds[i].size();j++)
{
curhv[idx[i][j]].push_back(dep[idx[i][j]]+eds[i][j].S-eds[i][j].F);
}
vector<ll> ord=idx[i];
sort(ord.begin(),ord.end(),cmp);
for(j=0;j<qry[i].size();j++)
{
ll l=qry[i][j].F,id=qry[i][j].S;
for(x=0;x<ord.size()&&curhv[ord[x]].size()>=i-l+1;x++)
{
ans[id]=min(ans[id],curhv[ord[x]][curhv[ord[x]].size()-(i-l+1)]-dep[ord[x]]);
}
}
for(j=0;j<eds[i].size();j++)
{
x=idx[i][j];
if(curhv[fa[x]].size()<curhv[x].size())
{
swap(curhv[fa[x]],curhv[x]);
}
for(k=0;k<curhv[x].size();k++)
{
curhv[fa[x]][curhv[fa[x]].size()-(curhv[x].size()-k)]=min(curhv[fa[x]][curhv[fa[x]].size()-(curhv[x].size()-k)],curhv[x][k]);
}
}
}
for(i=0;i<q;i++)
{
printf("%lld\n",ans[i]);
}
return 0;
}
有一棵
想要确定树的形态则肯定需要通过某种方式遍历整棵树。如果我们想采用类似 dfs 的方式,那么问题在于无法确定什么时候一个点的儿子被访问完了。注意到这个题目给出的距离第
具体来说,不妨设
这样朴素实现的话最坏需要
#include "island.h"
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define maxn 310
using namespace std;
ll n,res[maxn][maxn];
bool vis[maxn];
ll ask(ll x,ll k)
{
if(res[x][k]!=-1)
{
return res[x][k];
}
return res[x][k]=query(x,k);
}
void solve(int _n,int lim)
{
ll i,j;
memset(res,-1,sizeof(res));
n=_n;
vis[1]=true;
for(i=1;i<n;i++)
{
ll x=ask(1,i);
if(vis[x])
{
continue;
}
vis[x]=true;
for(j=1;j<n;j++)
{
ll y=ask(x,j);
answer(x,y);
if(vis[y])
{
break;
}
vis[y]=true;
}
}
return;
}
构造一个恰好有
竞赛图的三元环数量是一个经典问题,它等于
这样我们只需要求出一个序列
然后通过打表或根据直觉可以猜测只符合这个下界和上界的限制就一定有解。这个可以通过后面的构造的过程来完成证明。先考虑怎么构造。我们从大往小来确定每个
于是就做完了,直接贪心尝试每种权值是否可行即可。复杂度
#include <bits/stdc++.h>
#define INF 1000000000
#define LINF 1000000000000000000
#define MOD 1000000007
#define mod 998244353
#define F first
#define S second
#define ll long long
#define N 5010
using namespace std;
ll n,m,d[N];
bool ans[N][N];
ll calc(ll x,ll y)
{
ll tot=(y/x)*(y/x-1)/2;
tot*=(x-y%x);
tot+=(y%x)*(y/x)*(y/x+1)/2;
return tot;
}
bool cmp(pair<ll,ll> x,pair<ll,ll> y)
{
return x.F==y.F?x.S>y.S:x.F<y.F;
}
int main(){
ll T,i,j;
cin>>T;
while(T--)
{
cin>>n>>m;
m=n*(n-1)*(n-2)/6-m;
if(m<calc(n,n*(n-1)/2))
{
puts("No");
continue;
}
ll lft=n*(n-1)/2,lst=n-1;
for(i=n-1;i>0;i--)
{
for(j=lst;j>=0;j--)
{
if(lft-j>=i*(i-1)/2&&m-j*(j-1)/2>=calc(i,lft-j))
{
break;
}
}
assert(j>=0);
m-=j*(j-1)/2;
d[i]=j;
lst=j;
lft-=j;
}
assert(lft<=lst&&m==lft*(lft-1)/2);
d[0]=lft;
puts("Yes");
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
ans[i][j]=false;
}
}
priority_queue<pair<ll,ll> > pq;
for(i=0;i<n;i++)
{
pq.push(make_pair(d[i],i));
}
for(i=n-1;i>=0;i--)
{
vector<pair<ll,ll> > nds;
for(j=0;j<i;j++)
{
nds.push_back(make_pair(d[j],j));
}
sort(nds.begin(),nds.end(),cmp);
for(j=0;j<d[i];j++)
{
ans[i][nds[j].S]=true;
}
for(j=d[i];j<nds.size();j++)
{
ans[nds[j].S][i]=true;
d[nds[j].S]--;
}
}
for(i=1;i<n;i++)
{
for(j=0;j<i;j++)
{
putchar(ans[i][j]?'0':'1');
}
puts("");
}
}
return 0;
}