noip模拟6
T1 辣鸡
考时操作
盲打暴力+剪枝优化..
然后自以为看到了数据范围 1e9 之后还写了一个亿进制的高精度..
结果人家数据水得一批..
直接原地跳楼..
考后反思
就是一个排序优化+暴力..
这里的排序就是为了免得无效访问过多..
学会剪枝加暴力..全家省队没问题..
#include<bits/stdc++.h> using namespace std; #define ll long long int #define re register ll #define mp make_pair const ll N=100050; inline void read(ll &ss) { ss=0; ll cit=0; char ch; ch=getchar(); while((ch>'9') or (ch<'0')) { if(ch=='-') cit=1; ch=getchar(); } while((ch<='9') and (ch>='0')) { ss=(ss<<3)+(ss<<1)+(ch^48); ch=getchar(); } if(cit) ss=-ss; } ll n; ll sum; struct Square { ll x,y; ll x2,y2; }a[N]; inline bool cmp(Square aa,Square bb) { if(aa.x==bb.x) return aa.y<bb.y; return aa.x<bb.x; } inline void Work_1(ll i,ll j) { /* if(a[i].x==a[j].x) { if(a[i].x2=a[j].x2) { sum+=(a[i].x2-x[i].x)*2; } else sum+=min(a[i].x2-a[i].x,a[j].x2-a[j].x)*2+1; return ; } */ if(a[i].y2==a[j].y-1 or a[i].y==a[j].y2+1) { sum+=(min(a[i].x2,a[j].x2)-a[j].x+1)*2; if(a[i].x==a[j].x) --sum; if(a[i].x2==a[j].x2) --sum; } return ; } inline void Work_2(ll i,ll j) { if(a[i].y>a[j].y2+1 or a[i].y2<a[j].y-1) { return ; } if(a[i].y2==a[j].y-1 or a[i].y==a[j].y2+1) { ++sum; return ; } if(a[i].y2==a[j].y2 and a[i].y!=a[j].y) { sum+=min(a[i].y2-a[i].y,a[j].y2-a[j].y)*2+1; return ; } if(a[i].y2!=a[j].y2 and a[i].y==a[j].y) { sum+=min(a[i].y2-a[i].y,a[j].y2-a[j].y)*2+1; return ; } if(a[i].y2<a[j].y2 and a[i].y>a[j].y) { sum+=(a[i].y2-a[i].y+1)*2; return ; } if(a[i].y2>a[j].y2 and a[i].y<a[j].y) { sum+=(a[j].y2-a[j].y+1)*2; return ; } if(a[i].y2==a[j].y2 and a[i].y==a[j].y) { sum+=(a[i].y2-a[i].y)*2; return ; } if(a[i].y2<a[j].y2 and a[i].y<a[j].y) { sum+=(a[i].y2-a[j].y+1)*2; return ; } if(a[i].y2>a[j].y2 and a[i].y>a[j].y) { sum+=(a[j].y2-a[i].y+1)*2; return ; } } signed main() { read(n); for(re i=1;i<=n;++i) { read(a[i].x); read(a[i].y); read(a[i].x2); read(a[i].y2); sum+=(a[i].x2-a[i].x)*(a[i].y2-a[i].y)*2; } sort(a+1,a+1+n,cmp); for(re i=1;i<=n;++i) { for(re j=i+1;j<=n;++j) { if(a[j].x>a[i].x2+1) break; if(a[j].x<=a[i].x2) Work_1(i,j); if(a[j].x==a[i].x2+1) Work_2(i,j); //cout<<i<<" "<<j<<" "<<sum<<endl; } } printf("%lld",sum); return 0; }
T2 模板
考时操作
我只能说我没学过启发式合并..
而且我的代码写了一个和内置函数名重名的变量..
所以再次斩获 0pts..
#include<bits/stdc++.h> using namespace std; #define ll int #define lf double #define mp make_pair const ll N=2e5+50; inline void read(ll &ss) { ss=0; bool cit=0; char ch; while(!isdigit(ch=getchar())) if(ch=='-') cit=1; while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar(); if(cit) ss=-ss; } ll n,m,ts; ll head[N],siz[N],fa[N],son[N],s[N]; ll lct[N],col[N],lsh[N]; ll tim[N],ans[N]; struct I { ll u,v,nxt; } a[N*2]; struct II { ll l,r,sum,bs,lazy; } tr[N*4]; // 线段树维护的是某个时间的各个属性.. vector<pair<ll,ll> > vec[N]; void add(ll u,ll v) { a[++ts].u=u; a[ts].v=v; a[ts].nxt=head[u]; head[u]=ts; } void spread(ll x) { //lazy 用来明确是否需要清空子孙,一个小的优化.. if(tr[x].lazy) { tr[x<<1].sum=0; tr[(x<<1)|1].sum=0; tr[x<<1].bs=0; tr[(x<<1)|1].bs=0; tr[x<<1].lazy=1; tr[(x<<1)|1].lazy=1; tr[x].lazy=0; } return ; } void update(ll x,ll pos,ll val,ll num) { if(tr[x].l==tr[x].r) { tr[x].sum+=val;//颜色种类个数 tr[x].bs+=num;//小球个数 return ; } spread(x); ll mid=(tr[x].l+tr[x].r)>>1; if(pos<=mid) update(x<<1,pos,val,num); else update((x<<1)|1,pos,val,num); tr[x].sum=tr[x<<1].sum+tr[(x<<1)|1].sum; tr[x].bs=tr[x<<1].bs+tr[(x<<1)|1].bs; return ; } void ins(ll x) { ll u,v; for(ll i=0;i<vec[x].size();i++) { u=vec[x][i].first,v=vec[x][i].second; // 颜色 时间 // 由于对时间的上移,所以可以保证不会被颜色种类被算重.. if(!tim[u]) { update(1,v,1,1); tim[u]=v; } else { if(tim[u]>v) { update(1,tim[u],-1,0); update(1,v,1,1); tim[u]=v; } else update(1,v,0,1); } } return ; } ll ask(ll x,ll much) { if(much==0) return 0; if(tr[x].bs<=much) return tr[x].sum; spread(x); if(much<=tr[x<<1].bs) return ask(x<<1,much); else return tr[x<<1].sum+ask((x<<1)|1,much-tr[x<<1].bs); } void dfs1(ll now,ll dad) { fa[now]=dad; siz[now]=vec[now].size(); for(ll i=head[now];i;i=a[i].nxt) { if(a[i].v==dad) continue; dfs1(a[i].v,now); siz[now]+=siz[a[i].v]; if(siz[a[i].v]>siz[son[now]]) son[now]=a[i].v; // 根据颜色个数分布重儿子.. } return ; } void clear(ll x) { ll u; tr[1].sum=0; tr[1].bs=0; tr[1].lazy=1; for(ll i=0;i<vec[x].size();i++) { u=vec[x][i].first; tim[u]=0; //不使用memset,从而达到一个不止于优化的优化.. } return ; } void dfs2(ll now,ll dad) { //始终让重儿子的数值位于树中,又是一把优化,即上文不使用memset的原因之一.. for(ll i=head[now];i;i=a[i].nxt) { if(a[i].v==dad or a[i].v==son[now]) continue; dfs2(a[i].v,now); clear(a[i].v); } if(son[now]) dfs2(son[now],now); ins(now); for(ll i=head[now];i;i=a[i].nxt) { if(a[i].v==dad or a[i].v==son[now]) continue; ins(a[i].v); } ans[now]=ask(1,s[now]); if(son[now]) { for(ll i=0;i<vec[now].size();i++) { vec[son[now]].push_back(vec[now][i]); } vec[now].clear(); swap(vec[now],vec[son[now]]); for(ll i=head[now];i;i=a[i].nxt) { if(a[i].v==dad or a[i].v==son[now]) continue; for(ll j=0;j<vec[a[i].v].size();j++) { vec[now].push_back(vec[a[i].v][j]); } vec[a[i].v].clear(); } } return ; } void build(ll x,ll l,ll r) { tr[x].l=l; tr[x].r=r; if(l==r) return ; ll mid=(l+r)>>1; build(x<<1,l,mid); build((x<<1)|1,mid+1,r); return ; } signed main() { read(n); ll u,v,sum; for(ll i=1;i<=n-1;i++) { read(u); read(v); add(u,v); add(v,u); } for(ll i=1;i<=n;i++) read(s[i]); read(m); for(ll i=1;i<=m;i++) { read(lct[i]); read(col[i]); lsh[i]=col[i]; } build(1,1,m); sort(lsh+1,lsh+1+m); sum=unique(lsh+1,lsh+1+m)-lsh-1; for(ll i=1;i<=m;i++) { col[i]=lower_bound(lsh+1,lsh+1+sum,col[i])-lsh; vec[lct[i]].push_back(mp(col[i],i)); } dfs1(1,0); memset(siz,0,sizeof siz); dfs2(1,0); read(m); for(ll i=1;i<=m;i++) { read(u); printf("%d\n",ans[u]); } return 0; }
T3 大佬
考时操作
我选择了深搜..可是深搜没有选择我..
考后反思
这是一道方法多种多样的题目..
组合数..递推..等等..
这里转下学长的博客 --skyh
套中套..
#include<bits/stdc++.h> using namespace std; #define ll long long int #define re register ll const ll mod=1000000007; inline void read(ll &ss) { ss=0; ll cit=0; char ch; ch=getchar(); while((ch>'9') or (ch<'0')) { if(ch=='-') cit=1; ch=getchar(); } while((ch<='9') and (ch>='0')) { ss=(ss<<3)+(ss<<1)+(ch^48); ch=getchar(); } if(cit) ss=-ss; } ll n; ll m; ll k; ll val[2000000]; ll ans; inline ll mont(ll a,ll b,ll c) { ll temp=1; a=a%c; while(b>0) { if(b&1) temp=(temp*a)%c; b=b>>1; a=(a*a)%c; } return temp; } signed main() { read(n); read(m); read(k); if(k>n) { cout<<0; return 0; } for(re i=1;i<=m;++i) { read(val[i]); } ll temp1,temp2; for(re i=m;i>=1;--i) { temp1=1; temp2=1; for(re j=1;j<=k;++j) { temp1=(temp1*i)%mod; temp2=(temp2*(i-1))%mod; } ans+=(temp1-temp2)*val[i]; ans=(ans+mod)%mod; } ll rate=1; for(re i=1;i<=k;++i) { rate=(rate*m)%mod; } ans=(ans*mont(rate,mod-2,mod)+mod)%mod; ans=(ans*(n-k+1)+mod)%mod; printf("%lld",ans); }
T4 宝藏
考时操作
又是一道我没看出来的状压..
考后反思
看了一下午..对正解的理解全都在码里面了..
#include<bits/stdc++.h> using namespace std; #define ll int #define re register ll const ll INF=0x3f3f3f3f; ll n,m,ts; ll from,to,value,ans; ll f[1<<18][18]; ll dis[20][20]; ll g[1<<19];//可以直接连通的点及其本身. //树的深度又叫做树的高度,即根固定,子节点到根节点的最远距离.. signed main() { cin>>n; cin>>m; if(m==0) { cout<<0<<endl; return 0; } const ll alls=(1<<n)-1; memset(dis,0x3f,sizeof dis); memset(f,0x3f,sizeof f); for(re i=1;i<=m;++i) { cin>>from>>to>>value; dis[from][to]=min(dis[from][to],value); dis[to][from]=dis[from][to]; } //预处理出各个状态直接连边可以达到的集合: for(re i=1;i<=alls;++i) { for(re j=1;j<=n;++j) { dis[j][j]=0; if((1<<(j-1)) & i) //j 属于 i { for(re k=1;k<=n;++k) { if(dis[j][k]!=INF) { g[i]|=(1<<(k-1)); //预处理出对于每个点的集合所能拓展出的集合 //其实也可以不预处理..只不过可能会时间久一点.. } } } } } for(re i=0;i<=n-1;++i) { f[1<<i][0]=0; } //对于每个点,显然把 ta 作为通向地面的点的时候 ta 的深度为 0 //更新值的大小: for(re i=1;i<=alls;++i) /*枚举集合,对于每个集合的子集,通过g[s]判断该子集是否 合法,如果合法,枚举所有需要被连向的点的最小边权求和 乘深度,作为答案*/ { for(re s=i-1;s;s=((s-1)&i)) //这个地方是在枚举i的所有非全集子集S作为前j - 1层的点,剩余点作为第j层的点 //注意是所有非全集子集,而不是只少了一个元素的子集..这里要理解..可以画画图.. //因为 i 可以通过很多种方式转移过来,所以位于第 j 层的点可以不止一个.. { if((g[s] & i) == i) { ll sum=0; ll temp; ll ss=s xor i; //这里 ss 为 s 相对于 i 的补集..代表的是s可以直接连通且不包含其本身的集合.. for(re j=1;j<=n;++j) { if((1<<(j-1)) & ss) //s直接连一条边就可以连到 i,这里的g[s]包括其本身.. { temp=(ll)1e9; for(re k=1;k<=n;++k) //枚举最小边..触类旁通:由于这是一个图..所以成为i状态的方式有很多种.. { if((1<<(k-1)) & s) { temp=min(temp,dis[j][k]); } } sum+=temp; } } for(re j=1;j<=n;++j) { if(f[s][i-1]>=0) { // cout<<i<<" "<<j<<" "<<f[i][j]<<endl; // cout<<"f[s][j-1]:"<<f[s][j-1]<<" sum*j:"<<sum*j<<" "; // cout<<"s:"<<s<<endl; f[i][j]=min(f[i][j],f[s][j-1]+sum*j); // cout<<i<<" "<<j<<" "<<f[i][j]<<endl; } } } } } ans=1e9; for(re i=1;i<=n;++i)//枚举树高.. { ans=min(ans,f[alls][i]); } printf("%d",ans); return 0; }

浙公网安备 33010602011771号