noip模拟70[挺好]
noip模拟70 solutions
赛时排行榜好像还是挺好看的
嘿嘿,我还有一小会是第一呢,原因是人家的码还没有评测
然而我改题一点都改不动,一整个下午就一道题都没有调出来
除了我考场上切掉的那个题,就直接啥也不会
全是拍的
T1 暴雨
这个???拍的
大概意思好像是,先按照高度从大到小排序,然后向序列中一个一个的插入
这样我每次插入,就可以维护此时的奇偶性
至于你这数组如何开出来,因为你最多删掉25个所以最多有二十多个端点
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=25005;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,ans;
int a[N],p[N],jc[N];
int ys1[N],ny1,ys2[N],ny2;
int c1[30],n1,c2[30],n2,c3[30],n3,c4[30],n4;
int dp[2][27][27][27];
bool comp(int x,int y){return a[x]>a[y];}
void get(int &x){x=(x%mod+mod)%mod;}
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=1ll*ret*x%mod;
x=1ll*x*x%mod;y>>=1;
}return ret;
}
int C(int x,int y){return 1ll*jc[x]*ksm(1ll*jc[x-y]*jc[y]%mod,mod-2)%mod;}
signed main(){
#ifdef oj
freopen("rain.in","r",stdin);
freopen("rain.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
//n=read();m=read();
fo(i,1,n)scanf("%d",&a[i]),p[i]=i;
sort(p+1,p+n+1,comp);int now=0;
fo(i,1,n){now^=1;
memcpy(c3,c1,sizeof(c1));memcpy(c4,c2,sizeof(c2));n3=n1;n4=n2;
int h=p[i];c1[++n1]=h;c2[++n2]=h;
sort(c1+1,c1+n1+1);sort(c2+1,c2+n2+1,greater<int>());
n1=min(n1,m+1);n2=min(n2,m+1);
fo(j,1,n1)ys1[c1[j]]=j;
fo(j,1,n2)ys2[c2[j]]=j;
//cout<<"sb"<<i<<endl;
fo(l,1,n3)fo(r,1,n4)fo(k,0,m){
//cout<<"SB"<<endl;
if(dp[now^1][l][r][k]){
int x=c3[l],y=c4[r],v=dp[now^1][l][r][k];dp[now^1][l][r][k]=0;
//cout<<i<<" "<<l<<" "<<r<<" "<<v<<endl;
if(h<x){
if(((x-h-1)&a[h])&1)(dp[now][ys1[h]][ys2[y]][k]+=mod-v)%=mod;
else (dp[now][ys1[h]][ys2[y]][k]+=v)%=mod;
}
else if(h>y){
if(((h-y-1)&a[h])&1)(dp[now][ys1[x]][ys2[h]][k]+=mod-v)%=mod;
else (dp[now][ys1[x]][ys2[h]][k]+=v)%=mod;
//cout<<"this"<<" "<<(((h-y-1)&a[h])&1)<<" "<<v<<endl;
}
else {
if(a[h]&1)(dp[now][ys1[x]][ys2[y]][k]+=mod-v)%=mod;
else (dp[now][ys1[x]][ys2[y]][k]+=v)%=mod;
}
if(k)(dp[now][ys1[x]][ys2[y]][k-1]+=v)%=mod;
}
}
if(i-1<=m)(dp[now][ys1[h]][ys2[h]][m-i+1]+=1)%=mod;
}
fo(i,1,n1)fo(j,1,n2)ans=(ans+dp[now][i][j][0])%mod;//cout<<dp[now][i][j][0]<<" ";cout<<endl;
jc[0]=1;fo(i,1,n)jc[i]=1ll*jc[i-1]*i%mod;
int tot=C(n,m);//cout<<ans<<" "<<tot<<endl;
ans=(1ll*(1ll*tot+ans%mod+mod)*ksm(2,mod-2)%mod+mod)%mod;
printf("%d",ans);
}
T2 AVL树
这个就是我调了一下午但是啥结果都没有的题???
不知道是我能力不足还是咋地
我之前一直认为没有我认真调然后调不出来的题!!
但是这两天的题给我干傻了,真\(TM\)不会
原因是我一直只考虑了左子树深度对右子树的影响,并没有考虑原树的形态
可能之前一个大分叉,保证右边那颗子树深度必须大于某些东西
但是在右子树内,她的左子树深度不够,必须要用右子树,我没考虑这个
所以只需要记录一下,一直下放就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=5e5+5;
int n,k;
int rt,p[N],ls[N],rs[N];
queue<int> q;
int vis[N];
int f[N],dep[N],mxd[N];
int h[N],lh[N];
void dfs(int x){
dep[x]=dep[p[x]]+1;mxd[x]=dep[x];
if(ls[x])dfs(ls[x]),mxd[x]=max(mxd[x],mxd[ls[x]]);
if(rs[x])dfs(rs[x]),mxd[x]=max(mxd[x],mxd[rs[x]]);
}
bool chk(int x){
int ret=0,now=max(dep[x],h[x]);
//cout<<x<<endl;
while(~x){
if(!vis[x])ret++;
now=max(now,h[x]);
if(x<p[x])ret+=f[max(now-1,lh[rs[p[x]]])-dep[p[x]]];
x=p[x];
}
//cout<<x<<" "<<ret<<" "<<k<<endl;
return ret<=k;
}
void tag(int x){
h[x]=max(h[x],dep[x]);
int now=h[x];
while(~x){
h[x]=max(h[x],now);
if(!vis[x])vis[x]=1,k--;
if(x<p[x]&&rs[p[x]])lh[rs[p[x]]]=max(lh[rs[p[x]]],h[x]-1);
x=p[x];
}
}
void sol(int x){
if(chk(x))tag(x);
if(ls[x]&&rs[x]){
if(mxd[ls[x]]<lh[x])lh[rs[x]]=max(lh[rs[x]],lh[x]),lh[ls[x]]=max(lh[ls[x]],lh[x]-1);
else lh[ls[x]]=max(lh[ls[x]],lh[x]),lh[rs[x]]=max(lh[rs[x]],lh[x]-1);
sol(ls[x]);sol(rs[x]);
}
else {
if(ls[x])lh[ls[x]]=max(lh[ls[x]],lh[x]),sol(ls[x]);
if(rs[x])lh[rs[x]]=max(lh[rs[x]],lh[x]),sol(rs[x]);
}
}
signed main(){
#ifdef oj
freopen("avl.in","r",stdin);
freopen("avl.out","w",stdout);
#endif
scanf("%d%d",&n,&k);
fo(i,1,n){
scanf("%d",&p[i]);
if(p[i]==-1){rt=i;continue;}
if(i<p[i])ls[p[i]]=i;
else rs[p[i]]=i;
}
f[1]=1;fo(i,2,40)f[i]=f[i-1]+f[i-2]+1;
dfs(rt);sol(rt);fo(i,1,n)printf("%d",vis[i]);
}
T3 挖掘机
一看就是一层一层的消掉
一般这样的题的处理方式就是倍增
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int H=15;
const int W=1e5+5;
const int K=1e5+5;
int h,w,k,Q;
int jz[H][W];
int st[H][W][19];
int fir[H][W];
signed main(){
#ifdef oj
freopen("blueshit.in","r",stdin);
freopen("blueshit.out","w",stdout);
#endif
scanf("%d%d%d%d",&h,&w,&k,&Q);
memset(st,0x3f,sizeof(st));
memset(fir,0x3f,sizeof(fir));
fo(i,1,h){
char s[W];
scanf("%s",s+1);
fo(j,1,w){
if(s[j]=='X')jz[i][j]=1;
else jz[i][j]=0;
}
fu(j,w,1){
if(jz[i][j])fir[i][j]=j;
else fir[i][j]=fir[i][j+1];
if(jz[i][j])st[i][j][0]=fir[i][j+k];
else if(fir[i][j]<=w)st[i][j][0]=st[i][fir[i][j]][0];
for(int o=1;o<=18&&st[i][j][o-1]<=w;o++)st[i][j][o]=st[i][st[i][j][o-1]][o-1];
}
}
//cout<<"sb"<<" "<<fir[1][9]<<endl;
while(Q--){
int d,l,r;scanf("%d%d%d",&d,&l,&r);
int ans=0;
fo(i,1,d){
int now=l,res=0;
fu(j,18,0)if(st[i][now][j]<=r){
res+=(1<<j);
//cout<<i<<" "<<now<<" "<<j<<" "<<st[i][now][j]<<endl;
now=st[i][now][j];
}
if(!res&&fir[i][l]>r)res=0;
else res++;
ans+=res;//cout<<res<<endl;
}
printf("%d\n",ans);
}
}
T4 不会
QQ:2953174821