部分noip题解
NOIP2011
Mayan游戏
模拟题
比较有意思的搜索,需要剪枝
无脑枝:1.只有两个方块时直接return(不可能再消掉了) 2.不换颜色相同的
有脑枝:发现左移和右移其实是一样的,当前块与右面块交换等于右面块与当前块交换
然而左面为空时左移右移不同,特判一下
(其实就是向左移只当左面为空时才移,其他任意一种情况都与右移等价)
代码
#include<bits/stdc++.h> using namespace std; #define ll long long ll mp[8][6],vis[10][10],sta[10],del[10][10]; ll top,tt; const ll n=7,m=5; struct node{ ll x,y; node(){} node(const ll &a,const ll &b){x=a,y=b;} }; struct an{ ll x,y,g; an(){} an(const ll &a,const ll &b,const ll &c){x=a,y=b,g=c;} }ans[7]; deque<node> q,p; ll ok(ll x,ll y,ll opt){ if(x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]==opt&&!vis[x][y]) return 1; return 0; } void print(){ puts("wwb"); for(ll i=1;i<=n;i++,puts("")) for(ll j=1;j<=m;j++){ printf("%lld ",mp[i][j]); } } void down(){ for(ll i=1;i<=m;i++){ top=0; for(ll j=1;j<=n;j++) if(mp[j][i]) sta[++top]=mp[j][i]; for(ll j=1;j<=n;j++) mp[j][i]=0; for(ll j=1;j<=top;j++) mp[j][i]=sta[j]; } } void xiao(){ ll ok=0; down(); memset(del,0,sizeof(del)); for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++){ if(mp[i][j]){ if(i>1&&i<n){ if(mp[i][j]==mp[i+1][j]&&mp[i][j]==mp[i-1][j]){ del[i][j]=1,del[i+1][j]=1,del[i-1][j]=1; ok=1; } } if(j>1&&j<m){ if(mp[i][j]==mp[i][j-1]&&mp[i][j]==mp[i][j+1]){ del[i][j]=1,del[i][j-1]=1,del[i][j+1]=1; ok=1; } } } } if(!ok) return ; for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++) if(del[i][j]) mp[i][j]=0; down(); xiao(); return ; } ll ttt; ll check(){ for(ll i=1;i<=m;i++) if(mp[1][i]) return 0; return 1; } void cpy(ll x[][6],ll y[][6]){ for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++) x[i][j]=y[i][j]; } void dfs(ll cnt){ // printf("%lld\n",cnt); if(check()&&cnt==tt+1){ for(ll i=1;i<=tt;i++) printf("%lld %lld %lld\n",ans[i].x,ans[i].y,ans[i].g); exit(0); } if(cnt>=tt+1) return ; ll mem[8][6]; for(ll j=1;j<=m;j++) for(ll i=1;i<=n;i++){ if(mp[i][j]){ if(j!=m&&mp[i][j]!=mp[i][j+1]){ cpy(mem,mp); ans[++ttt]=an(j-1,i-1,1); swap(mp[i][j],mp[i][j+1]); xiao(); dfs(cnt+1);ttt--; cpy(mp,mem); } if(j!=1&&mp[i][j]!=mp[i][j-1]){ cpy(mem,mp); ans[++ttt]=an(j-1,i-1,-1); swap(mp[i][j],mp[i][j-1]); xiao(); dfs(cnt+1);ttt--; cpy(mp,mem); } } } } ll cnt[7]; int main(){ scanf("%lld",&tt);ll x; x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[1]][1]=x;} x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[2]][2]=x;} x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[3]][3]=x;} x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[4]][4]=x;} x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[5]][5]=x;} xiao(); dfs(1); puts("-1"); }
NOIP2014
联合权值
题解
花5分钟写了写
发现根本不用$Dp$,
$O(n^2)$,max显然就是最大值*次大值,总和思考怎么算
发现就是(sum[i]-w[y])*w[y],sum表示是所有与i相连点权值之和,
$O(n)$式子
显然可以优化,${sum[i]}^2-\sum\limits_{y}{w[y]}^2$随便维护一下
代码
#include<bits/stdc++.h> using namespace std; #define ll long long #define mod 10007 #define A 1111111 ll tot,n,m,t,ans,mx; ll sum[A],nxt[A],ver[A],x[A],y[A],head[A],w[A],maxx[A],cimaxx[A],pingf[A]; void add(ll x,ll y){ nxt[++tot]=head[x],head[x]=tot,ver[tot]=y; } int main(){ scanf("%lld",&n);m=n-1; for(ll i=1;i<=m;i++){ scanf("%lld%lld",&x[i],&y[i]); add(x[i],y[i]);add(y[i],x[i]); } for(ll i=1;i<=n;i++){ scanf("%lld",&w[i]); } for(ll i=1;i<=m;i++){ (sum[x[i]]+=w[y[i]])%=mod,(sum[y[i]]+=w[x[i]])%=mod; (pingf[x[i]]+=w[y[i]]*w[y[i]])%=mod; (pingf[y[i]]+=w[x[i]]*w[x[i]])%=mod; if(w[y[i]]>maxx[x[i]]){ cimaxx[x[i]]=maxx[x[i]]; maxx[x[i]]=w[y[i]]; } else if(w[y[i]]>cimaxx[x[i]]){ cimaxx[x[i]]=w[y[i]]; } if(w[x[i]]>maxx[y[i]]){ cimaxx[y[i]]=maxx[y[i]]; maxx[y[i]]=w[x[i]]; } else if(w[x[i]]>cimaxx[y[i]]){ cimaxx[y[i]]=w[x[i]]; } } for(ll i=1;i<=n;i++){ (ans+=sum[i]*sum[i]%mod-pingf[i])%mod; mx=max(cimaxx[i]*maxx[i],mx); } ans%=mod; printf("%lld ",mx); printf("%lld\n",(ans+mod)%mod); }
NOIP2016
蚯蚓
题解
暴力就是开一个堆维护,然后每次取出最大值,维护mark表示标准差可以85分
正解是根据单调性不算标准差
因为每次取出最大值,取出的最大值越来小,另外维护两个队列,维护切出的两部分蚯蚓
剩下两部分蚯蚓也满足单调不升性质
单调队列维护
代码
#include<bits/stdc++.h> using namespace std; #define ll long long deque<ll> w[4]; ll n,m,q,u,v,t; ll mark,cnt,mxid,mx; ll ans[31111111],dl[31111111],o[31111111]; double p; ll cmp(ll x,ll y){ return x>y; } ll gettop(){ mx=-123456789101112,mxid=0; if(!w[1].empty()){ if(w[1].front()>mx){ mx=w[1].front(); mxid=1; } } if(!w[2].empty()){ if(w[2].front()>mx){ mx=w[2].front(); mxid=2; } } if(!w[3].empty()){ if(w[3].front()>mx){ mx=w[3].front(); mxid=3; } } w[mxid].pop_front(); return mx; } ll wempty(){ if(w[1].empty()&&w[2].empty()&&w[3].empty()) return 1; return 0; } int main(){ scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t); for(ll i=1;i<=n;i++){ scanf("%lld",&o[i]); } sort(o+1,o+n+1,cmp); for(ll i=1;i<=n;i++){ w[1].push_back(o[i]); } p=(double)(u)/(double)(v); for(ll i=1;i<=m;i++){ ll x=gettop()+mark; double xx=p*x; ll x1=floor(p*x),x2=x-x1; mark+=q; w[2].push_back(x1-mark),w[3].push_back(x2-mark); ans[i]=x; } while(!wempty()){ dl[++dl[0]]=gettop()+mark; } for(ll i=t;i<=m;i+=t) printf("%lld ",ans[i]); printf("\n"); for(ll i=t;i<=dl[0];i+=t) printf("%lld ",dl[i]); printf("\n"); }
NOIP2017
列队
题解
易发现m列有些特殊
前m-1列和m列拆开考虑
开n棵线段树维护n行,在开一棵线段树维护最后一列
每一次操作可简化为
依次进行 1.当前行删除y 2.当前行前移 3.最后列删除x 4.最后列前移
线段树维护查询第k大操作
代码实现有很多技巧,很考验代码能力
代码
//依次进行 //1.当前行删除y //2.当前行前移 //3.最后列删除x //4.最后列前移 #include<bits/stdc++.h> using namespace std; #define ll long long #define A 11111111 vector<ll> vec[A]; ll ls[A],rs[A],v[A],toot[A]; ll n,m,tot,cnt,q; void change(ll &x,ll l,ll r,ll val){ if(!x) x=++cnt; v[x]++; if(l==r) return ; ll mid=(l+r)>>1; if(mid>=val) change(ls[x],l,mid,val); else change(rs[x],mid+1,r,val); } ll ask(ll &x,ll l,ll r,ll k){ if(l==r) return l; ll mid=(l+r)>>1; ll sum=mid-l+1-v[ls[x]]; if(sum>=k) return ask(ls[x],l,mid,k); else return ask(rs[x],mid+1,r,k-sum); } ll callast(ll x){ //查询最后一列 ll r=ask(toot[n+1],1,tot,x); change(toot[n+1],1,tot,r); return r<=n?(r-1)*m+m:vec[n+1][r-n-1]; } ll calcommon(ll x,ll y){ ll r=ask(toot[x],1,tot,y); change(toot[x],1,tot,r); return r<m?(x-1)*m+r:vec[x][r-m]; } int main(){ ll ret,tmp; scanf("%lld%lld%lld",&n,&m,&q); tot=max(n,m)+q; while(q--){ ll x,y; scanf("%lld%lld",&x,&y); if(y==m){ ret=callast(x); vec[n+1].push_back(ret); printf("%lld\n",ret); } else{ ret=calcommon(x,y); printf("%lld\n",ret); vec[n+1].push_back(ret); tmp=callast(x); vec[x].push_back(tmp); } } }
NOIP2018
货币系统
题解
性质,1.最简系统一定是给定系统子集
2.最简系统任意一种货币不能被其他货币表示
2是显然的
1证明:假设非子集元素为x
若x可以被最简系统表示加入它没用,若不能被表示出,你原本不能表示x,现在加上x可以表示x与最简系统矛盾了
所以可以无脑背包
我已没有下降的余地