CSP-S模拟12
下发文件和题解
由于题面在网上已经可以查询到,故放出题面,但仍请不要随意发布至网络上.
A. 开挂
题目描述
用一个栈,每次出现一个和前面相等的数就放入栈中,出现不相等的数就看它和上一个数之间有多少空位,每次贪心地选栈顶的与之配对.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define rg register
#define sinline static inline
#define rll rg ull
#define maxn 1000010
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ull read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
return f?-x:x;
}
sinline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ull n,ls,num=1,len,it,s;
ull ans;
ull a[maxn],b[maxn];
vector<ull> c,d;
int main()
{
n=read();for(rll i=1;i<=n;i++) a[i]=read();for(rll i=1;i<=n;i++) b[i]=read();
sort(a+1,a+n+1);sort(b+1,b+n+1);
for(rll i=1;i<=n+1;i++)
{
if(a[i]!=a[i-1])
{
while((a[i]^ls)&&(!c.empty()))
d.push_back(ls-c.back()),c.pop_back(),ls++;
ls=a[i]+1;
}
else c.push_back(a[i]);
}
sort(d.begin(),d.end());s=d.size();
for(rll i=1;i<=s;i++) ans+=d[s-i]*b[i];write(ans);
return 0;
}
B. 叁仟柒佰万
题目描述
首先,如果每个子序列的 mex 值相同,那么每一个子序列上的 mex 值一定是整个序列的 mex 值.
那么显然这是一道 dp 题. 令 dp[i] 表示前 i 个点,它的 mex 相同的段有多少种可能. 然后用一个双指针扫一遍记录答案. 发现前面有一大部分可能没有贡献(即 mex 小于整个序列的),直接记录 sum 忽略它们从后面开始 dp.
点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 37000001
#define mod 1000000007
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
return f?-x:x;
}
sinline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ll t,n,x,y,mx,tmx,k,s;
ll a[maxn],sum[maxn],dp[maxn];
bool fl[maxn],flag;
// sinline ll ksm(rll a,rll b) { rll ans=1; a%=mod; for(rll i=b;i;i>>=1) { if(i&1) ans=ans*a%mod; a=a*a%mod; } return ans; }
int main()
{
t=read();while(t--)
{
memset(fl,0,sizeof(fl));memset(sum,0,sizeof(sum));memset(dp,0,sizeof(dp));flag=tmx=mx=0;
if((n=read())==37000000) { x=read(); y=read(); a[1]=0; for(rll i=2;i<=n;i++) a[i]=(a[i-1]*x+y+i)&262143; }
else for(rll i=1;i<=n;i++) a[i]=read();
for(rll i=1;i<=n;i++) if(!a[i]) { flag=1;break; }
// if(!flag) { write(ksm(2,n-1)); putn; continue; }
for(rll i=1;i<=n;i++) { fl[a[i]]=1;if(mx==a[i]) while(fl[mx]) mx++; }
memset(fl,0,sizeof(fl));
for(k=1;k<=n;k++) { sum[a[k]]++; fl[a[k]]=1; if(tmx==a[k]) while(fl[tmx]) tmx++; if(tmx==mx) break; }
s=dp[0]=dp[k]=1;
for(rll i=k+1,r=1;i<=n;i++)
{
sum[a[i]]++;
while(r<i&&(a[r]>mx||sum[a[r]]>1))
{
if(r>=k) s=(s+dp[r])%mod;sum[a[r]]--;r++;
}
dp[i]=s;// cout<<dp[i]<<' ';
}
/*putn;*/write(dp[n]);putn;
}
return 0;
}
C. 超级加倍
题目描述
类似于一个 kruskal 重构树的做法.
把笛卡尔树的做法拓展到树上.
对于求这种路径显然是一个范围问题. 从小到大加入每个节点,对于每新加入的节点 v,合并已加入节点 u 和 v,把 u 连通块的根设置为 v,自然并查集就行了.
重构树上的两个点的 lca 就是真实路径上的最小值.
所以可以反过来重新建一棵树,这样两个点的 lca 就是真实路径上的最大值了.
所以在第一棵树上求 dfs 序。在第二棵树上遍历,用一个 bit 统计答案即可.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 2000001
#define elif else if
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
return f?-x:x;
}
sinline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
template<typename T,size_t sz>
class bit
{
#define lowbit(x) (x&-x)
private:
T c[sz];
public:
inline void update(rg T x,rg T n,rg T v) { for(rg T i=x;i<=n;i+=lowbit(i)) c[i]+=v; }
inline T query(rg T x) { /*write(x);putn;*/ rg T ans=0; for(rg T i=x;i;i-=lowbit(i)) ans+=c[i]; /*write(ans);putn;*/ return ans; }
#undef lowbit
};
ll n,f[maxn],dfn[maxn],sz[maxn],cnt,ans;
vector<ll> g[maxn],g1[maxn]/*重构树*/;
bit<ll,maxn> t;
sinline ll find(rll x) { if(x!=f[x]) f[x]=find(f[x]); return f[x]; }
sinline void dfs(rll x)
{
dfn[x]=++cnt;sz[x]=1;// cout<<x<<' '<<dfn[x]<<endl;
for(rll i=0;i<g1[x].size();i++) { rll to=g1[x][i]; dfs(to); sz[x]+=sz[to]; }
}
sinline void dfs1(rll x)
{
// cout<<x<<' '<<dfn[x]<<endl;
ans+=t.query(dfn[x]+sz[x]-1)-t.query(dfn[x]-1);
t.update(dfn[x],n,1);// write(t.query(dfn[x]));
for(rll i=0;i<g1[x].size();i++) { rll to=g1[x][i]; dfs1(to); }
t.update(dfn[x],n,-1);
}
int main()
{
n=read();for(rll i=1,t;i<=n;i++) t=read(),g[t].push_back(i),g[i].push_back(t);
for(rll i=1;i<=n;i++) f[i]=i;
for(rll i=n-1;i;i--)
for(rll j=0;j<g[i].size();j++)
{
rll to=g[i][j];if(to>i) g1[i].push_back(find(to)),f[find(to)]=i;
}
dfs(1);for(rll i=1;i<=n;i++) f[i]=i;for(rll i=1;i<=n;i++) g1[i].clear();
for(rll i=2;i<=n;i++)
for(rll j=0;j<g[i].size();j++)
{
rll to=g[i][j];if(to<i) g1[i].push_back(find(to)),f[find(to)]=i;
}
dfs1(n);write(ans);
return 0;
}
D. 欢乐豆
题目描述
贺的(原网址).
点击查看代码
#include<bits/extc++.h>
#define ll long long
#define rg register
#define sinline static inline
#define rll rg ll
#define maxn 200001
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
sinline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
return f?-x:x;
}
sinline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
struct node
{
ll v,id;
inline friend bool operator<(rg node a,rg node b) { return a.v<b.v; }
}b[maxn];
struct tree
{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
ll mnv,pos,tag;
}t[maxn<<2];
ll n,m,x,y,z,k,tot,ans;
ll a[maxn],f[maxn];
ll id[maxn],num[maxn],dis[maxn];
vector<ll> g[maxn];
vector<pll> h,g1[maxn];
struct nd
{
ll a,b;
inline friend bool operator<(rg nd a,rg nd b) { return id[a.a]<id[b.a]; }
};
vector<nd> q;
multiset<ll> s;
__gnu_pbds::list_update<pll,ll> mp;
sinline ll find(rll x) { if(x^f[x]) f[x]=find(f[x]); return f[x]; }
sinline void pushup(rll rt)
{
if(t[ls(rt)].mnv==t[rs(rt)].mnv&&t[ls(rt)].mnv==-1) { t[rt].mnv=-1; return; }
if((!~t[ls(rt)].mnv)||(t[ls(rt)].mnv>t[rs(rt)].mnv&&(~t[rs(rt)].mnv))) t[rt].mnv=t[rs(rt)].mnv,t[rt].pos=t[rs(rt)].pos;
else t[rt].mnv=t[ls(rt)].mnv,t[rt].pos=t[ls(rt)].pos;
}
sinline void pushdown(rll rt)
{
if(t[rt].tag!=(INT_MAX))
{
t[ls(rt)].mnv=min(t[rt].tag,t[ls(rt)].mnv);t[ls(rt)].tag=min(t[rt].tag,t[ls(rt)].tag);
t[rs(rt)].mnv=min(t[rt].tag,t[rs(rt)].mnv);t[rs(rt)].tag=min(t[rt].tag,t[rs(rt)].tag);
t[rt].tag=(INT_MAX);
}
}
sinline void build(rll rt,rll l,rll r)
{
t[rt].mnv=t[rt].tag=(INT_MAX);
if(l==r) { t[rt].pos=num[l]; return; }
rll mid=(l+r)>>1;
build(ls(rt),l,mid); build(rs(rt),mid+1,r);
pushup(rt);
}
sinline void upd(rll rt,rll l,rll r,rll x,rll y,rll v)
{
if(x<=l&&r<=y) { t[rt].mnv=min(t[rt].mnv,v); t[rt].tag=min(t[rt].tag,v); return; }
pushdown(rt);rll mid=(l+r)>>1;
if(x<=mid) upd(ls(rt),l,mid,x,y,v);if(y>mid) upd(rs(rt),mid+1,r,x,y,v);
pushup(rt);
}
sinline ll query(rll rt,rll l,rll r,rll pos)
{
if(l==r) return t[rt].mnv;
if(t[rt].tag!=(INT_MAX)) pushdown(rt);
rll mid=(l+r)>>1;
if(pos<=mid) return query(ls(rt),l,mid,pos);
else return query(rs(rt),mid+1,r,pos);
}
sinline void spfa(rll x)
{
upd(1,1,tot,id[x],id[x],0);
while(~t[1].mnv)
{
rll p=t[1].pos,d=t[1].mnv,ls=0; dis[p]=d;
q.clear();
for(rll i=0;i<g1[p].size();i++) q.push_back((nd) { g1[p][i].first,g1[p][i].second });
sort(q.begin(),q.end());
for(rll i=0;i<q.size();i++)
{
rll ta=q[i].a,mnd=d+min(q[i].b,a[p]+k);
if(ls+1<=id[ta]-1) upd(1,1,tot,ls+1,id[ta]-1,d+a[p]);ls=id[ta];
if(query(1,1,tot,id[ta])>mnd) upd(1,1,tot,id[ta],id[ta],mnd);
}
if(ls+1<=tot) upd(1,1,tot,ls+1,tot,d+a[p]);
upd(1,1,tot,id[p],id[p],-1);
}
}
sinline void get(rll x)
{
for(rll i=0;i<g[x].size();i++) s.erase(s.find(a[g[x][i]]));
if(!s.empty()) k=*s.begin(); else k=(INT_MAX);
tot=0;
for(rll j=0;j<g[x].size();j++) id[g[x][j]]=++tot,num[tot]=g[x][j];
for(rll i=0;i<g[x].size();i++)
{
build(1,1,tot);spfa(g[x][i]);
for(rll j=0;j<g[x].size();j++) ans+=dis[g[x][j]];
rll k=a[g[x][i]];
for(rll j=0;j<g[x].size();j++) k=min(k,dis[g[x][j]]+a[g[x][j]]);
ans+=(n-g[x].size())*k;
}
for(rll i=0;i<g[x].size();i++) s.insert(a[g[x][i]]);
}
int main()
{
n=read();m=read();for(rll i=1;i<=n;i++) a[i]=read(),s.insert(a[i]),f[i]=i;
for(rll i=1,ls;i<=m;i++)
{
x=read();y=read();z=read();
if(find(x)!=find(y)) f[find(x)]=find(y);
if(!mp[(pll) { x,y }]) h.push_back((pll) { x,y });
mp[(pll) { x,y }]=z;
}
for(rll i=0;i<h.size();i++)
g1[h[i].first].push_back((pll) { h[i].second,mp[(pll) { h[i].first,h[i].second }] });
for(rll i=1;i<=n;i++) g[find(i)].push_back(i);
for(rll i=1;i<=n;i++)
{
if(g[find(i)].size()==1) ans+=(n-1)*a[i];
else if(find(i)==i) get(find(i));
}
write(ans);
return 0;
}
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16731507.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!