noip模拟43
A. 第一题
考场上打的线段树合并\(+\)贪心假了..
贪心应该是正解,但是\(dp\)也可做..
想着线段树合并时间复杂度可以稍微小一点.
于是放弃了每次使用\(set\)维护,但是其实也能过.
结果\(Vector\)暴力扫\(+\)排序维护也能\(A\).
一般的话,如果是二叉树,复杂度为\(O(nlogn)\),但是链的话可以卡成\(O(n)\).
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll long long int
#define re register ll
#define lf double
#define lbt(x) (x&(-x))
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=1e5+51;
ll m,n,ts,ans;
ll head[N],rt[N<<6];
vector<ll> vec[N];
struct I { ll u,v,nxt; } e[N<<1];
inline void add(ll u,ll v){
e[++ts].u=u,e[ts].v=v,e[ts].nxt=head[u];
head[u]=ts;
}
inline bool comp(ll i,ll j){ return i>j; }
void dfs(ll now,ll dad,ll dep){
ll flag=1;
for(re i=head[now];i;i=e[i].nxt){
if(e[i].v==dad) continue;
flag=0; dfs(e[i].v,now,dep+1);
if(vec[now].size()<vec[e[i].v].size()) swap(vec[e[i].v],vec[now]);
for(auto j : vec[e[i].v]) vec[now].push_back(j);
}
if(flag){
vec[now].push_back(dep);
ans+=dep;
return ;
}
// cout<<"Now:"<<now<<" "<<ans<<'\n';
// for(auto i : vec[now]) cout<<i<<" ";
// cout<<'\n';
sort(vec[now].begin(),vec[now].end(),comp);
if(vec[now].size())
for(ll i=vec[now].size()-1;i>=1;--i){
if(vec[now][i]>=2*dep) break;
ans+=vec[now][i]-2*dep;
flag++;
}
while((flag--) and vec[now].size()){
vec[now].pop_back();
}
return ;
}
signed main(){
n=read(); ll u,v;
if(n==1){ cout<<0; return 0; }
for(re i=2;i<=n;i++) u=read(),v=read(),add(u,v),add(v,u);
dfs(1,0,0);
printf("%lld\n",ans);
return 0;
}
B. 第二题
没有看到单调性,直接挂了.
二分+\(Spfa\)乱跑就行..
每次将所有的点都压入队列,每枚举到一个点,然后就更新周围的六个就可以..
数据依旧过水,这套题的数据我真的没话说了.
复杂度 \(O(\)玄学\()\)
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll long long int
#define re register ll
#define lf double
#define lbt(x) (x&(-x))
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=1e5+51;
ll m,n,t,tot,ts;
ll val[N],head[N],vis[N];
map<pair<ll,ll>,ll> map1;
struct I { ll w; } p[N];
struct II { ll u,v,nxt; } e[N<<6];
inline void add(ll u,ll v){
e[++ts].u=u,e[ts].v=v,e[ts].nxt=head[u],
head[u]=ts;
}
queue<ll> que;
inline bool Spfa(ll x){
for(ll i=1;i<=tot;++i){
val[i]=p[i].w,vis[i]=1;
que.push(i);
}
ll now,res=0;
while(que.size()){
now=que.front(); que.pop();
for(re i=head[now];i;i=e[i].nxt){
if(val[e[i].v]-val[now]>x){
res+=val[e[i].v]-x-val[now],val[now]+=val[e[i].v]-x-val[now];
}
}
for(re i=head[now];i;i=e[i].nxt){
if(val[now]-val[e[i].v]>x){
res+=val[now]-x-val[e[i].v],val[e[i].v]+=val[now]-x-val[e[i].v];
if(!vis[e[i].v]) que.push(e[i].v);
vis[e[i].v]=1;
}
}
vis[now]=0;
}
// cout<<x<<" "<<res<<endl;
return res<=t;
}
inline void Work(){
ll l=0,r=1e12,res=r,mid;
while(l<=r){
mid=(l+r)>>1;
if(Spfa(mid)) r=mid-1,res=mid;
else l=mid+1;
}
printf("%lld",res);
return ;
}
signed main(){
n=read(),m=read(),t=read(); ll x,y,temp;
for(ll i=1;i<=n;++i)
for(ll j=1;j<=m;++j)
p[++tot].w=read(),map1[mp(i,j)]=tot;
for(ll i=1;i<=n;++i){
for(ll j=1;j<=m;++j){
if(j>1) add(map1[mp(i,j)],map1[mp(i,j-1)]);
if(j<m) add(map1[mp(i,j)],map1[mp(i,j+1)]);
if(i>1) add(map1[mp(i,j)],map1[mp(i-1,j)]);
if(i>1 and j<m) add(map1[mp(i,j)],map1[mp(i-1,j+1)]);
if(i<n and j>1) add(map1[mp(i,j)],map1[mp(i+1,j-1)]);
if(i<n) add(map1[mp(i,j)],map1[mp(i+1,j)]);
}
}
Work();
return 0;
}
C. 第三题
思路来自 \(Yubai\).
设 \(solve(x)\) 表示求出排名在 \(x\) 以内,值域在 \([L,R]\) 之间的和.
所以答案就是 \(solve(b)-solve(a-1)\).
考虑如何解决 \(solve(x)\).
由于 ta 是按照从大到小排序的,所以我们可以倒序枚举二进制位上 \(1\) 的个数.
考虑求出相应二进制位下值域位于 \([L,R]\) 的数的个数.
然后我们求出前几个二进制位下的总和就可以了.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:-w;
}
} using namespace BSS;
const ll N=35;
ll Ts,L,R,ql,qr;
ll f[N][N],g[N][N];
ll dfs1(ll lmt,ll now,ll is){
if(is>now) return 0; if(!is) return 1; ll res=0;
if((lmt>>now-1)&1) res+=f[now-1][is],res+=dfs1(lmt,now-1,is-1);
else res+=dfs1(lmt,now-1,is);
return res;
}
ll dfs2(ll lmt,ll now,ll is){
if(is>now) return 0; if(!is) return 0; ll res=0;
if((lmt>>now-1)&1) res+=g[now-1][is],res+=dfs1(lmt,now-1,is-1)*(1ll<<now-1)+dfs2(lmt,now-1,is-1);
else res+=dfs2(lmt,now-1,is);
return res;
}
inline ll solve(ll x){
ll res=0,fs,gs;
for(ll i=30;i>=0;i--){
if(!x) break;
fs=dfs1(R,30,i)-dfs1(L-1,30,i); //cout<<fs<<' ';
if(x>=fs) x-=fs,res+=dfs2(R,30,i)-dfs2(L-1,30,i);
else {
ll l=L-1,r=R,w,rw=dfs1(R,30,i);
while(l<=r){
ll mid=(l+r)>>1;
if(x>=rw-dfs1(mid,30,i)) r=mid-1,w=mid;
else l=mid+1;
}
res+=dfs2(R,30,i)-dfs2(w,30,i); break;
}
}
return res;
}
signed main(){
Ts=read();
for(ll i=0;i<=32;i++){
f[i][0]=1;
for(ll j=1;j<=i;j++){
f[i][j]=f[i-1][j-1]+f[i-1][j];
g[i][j]=g[i-1][j-1]+g[i-1][j]+(1ll<<i-1)*f[i-1][j-1];
}
}
while(Ts--){
L=read(),R=read(),ql=read(),qr=read();
printf("%lld\n",solve(qr)-solve(ql-1));
}
return 0;
}
D. 第四题
D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll long long int
#define lf double
#define re register ll
#define ull unsigned ll
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=3e3+21;
ll n,mod;
ll ans[N];
ll f[N][N],g[N][N],pre1[N][N],pre2[N][N];
signed main(){
n=read(),mod=read(),f[0][0]=1; ll res;
for(re i=1;i<=n;i++){
for(re j=1;j<=i;j++)
f[i][j]=(f[i-1][j]*j%mod+f[i-1][j-1])%mod;
}
for(re i=1;i<=n+1;i++) g[n+1][i]=1;
for(re i=n;i>=1;i--){
for(re j=n;j>=1;j--)
g[i][j]=(g[i+1][j+1]+g[i+1][j]*j%mod)%mod;
}
for(re i=1;i<=n;i++){
for(re j=n;j>=1;j--)
pre1[i][j]=(pre1[i][j+1]+f[i-1][j]*g[i+1][j]%mod)%mod,
pre2[i][j]=(pre2[i][j+1]+f[i-1][j]*g[i+2][j]%mod)%mod;
}
for(re i=1;i<=n;i++){
for(re j=1;j<=n;j++){
res=(pre1[i][j]+(n-i<<1)%mod*pre2[i][j]%mod)%mod,
(res+=f[i-1][j-1]*(g[i+1][j]+(n-i<<1)%mod*g[i+2][j]%mod)%mod)%=mod;
ans[j]=(ans[j]+res)%mod;
}
}
for(re i=1;i<=n;i++) printf("%lld ",ans[i]);
puts(""),exit(0);
}

浙公网安备 33010602011771号