多省联测2018
感觉这套题比较像比较正常的省选题呀
就是我可以做出来一两道,有一两道根本看不懂题解,非常有区分度(成功把我这个juruo区分出来)的题
D1T1
原来轮廓线dp就是这个……
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<map> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=13,W=10; const ll Bs=11,INF=1e14; int n,m,f[2][maxn][maxn]; ll mi[maxn],T; map<ll,ll> G,H; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } ll s(int p,ll t) { if(t==T) return 0; if(H[t]) return G[t]; ll rs=-INF,x,y; y=t%mi[1]; if(y!=m) rs=f[p][1][y+1]-s(p^1,t+1); For(i,2,n) { x=(t/mi[i-1])%mi[1]; if(x<y) rs=max(rs,f[p][i][x+1]-s(p^1,t+mi[i-1])); y=x; } H[t]=1; return G[t]=rs; } int main() { freopen("chess.in","r",stdin); freopen("chess.out","w",stdout); read(n); read(m); mi[0]=1; For(i,1,W) mi[i]=mi[i-1]*Bs; For(i,1,n) T=T*Bs+m; For(i,1,n) For(j,1,m) read(f[0][i][j]); For(i,1,n) For(j,1,m) read(f[1][i][j]); printf("%lld\n",s(0,0)); return 0; }
D1T2
场上写了个假算法,就是建树之后,一层一层贪心,写了3个线段树上二分,还有撤销操作。然而这个是假算法不是因为有相同值的原因……
关键点在于,如果你直接去确定这个子树占哪些位置怎样都是会出现问题的。所以我们只能说,在哪一块区域,我们给这个子树预订多少位置。
所以我们把d排好序之后(假如是从小到大排的),对于每个位置i,我们用线段树维护i及其右边的可用位置,就是i~n的所有位置减去i~n中预订了的位置。
于是我又写了3个线段树上二分,然而现在都还有10分WA着呢,调不出来呀orz,先放个90分代码在这好了。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=2e6+7; ll n,p[maxn],ld[maxn],rd[maxn],a[maxn],f[maxn],tot,ans[maxn]; db k; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[maxn],to[maxn],e=0; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; } int size[maxn]; void s(int pos) { size[pos]=1; int y,z; for(y=fir[pos];y;y=nxt[y]) { s(z=to[y]); size[pos]+=size[z]; } } ll sum[4*maxn],minnum[4*maxn],laz[4*maxn],ql,qr,qx; void ud(int pos) { sum[pos]=sum[pos<<1]+sum[pos<<1|1]; minnum[pos]=min(minnum[pos<<1],minnum[pos<<1|1]); } void pd(int pos) { if(!laz[pos]) return; minnum[pos<<1]+=laz[pos]; minnum[pos<<1|1]+=laz[pos]; laz[pos<<1]+=laz[pos]; laz[pos<<1|1]+=laz[pos]; laz[pos]=0; } void bld(int pos,int l,int r) { if(l==r) { sum[pos]=1; minnum[pos]=n-l+1; return; } int mid=(l+r)>>1; bld(pos<<1,l,mid); bld(pos<<1|1,mid+1,r); ud(pos); } void chge(int pos,int l,int r) { if(l>=ql&&r<=qr) { minnum[pos]+=qx; laz[pos]+=qx; return; } int mid=(l+r)>>1; pd(pos); if(ql<=mid) chge(pos<<1,l,mid); if(qr>mid) chge(pos<<1|1,mid+1,r); ud(pos); } void add(int pos,int l,int r) { sum[pos]+=qx; if(l==r) return; int mid=(l+r)>>1; pd(pos); if(ql<=mid) add(pos<<1,l,mid); else add(pos<<1|1,mid+1,r); } int find1(int pos,int l,int r) { if(minnum[pos]>=qx) return 0; if(l==r) return l; int mid=(l+r)>>1,rs=0; pd(pos); if(ql<=mid) rs=find1(pos<<1,l,mid); if(!rs&&qr>mid) rs=find1(pos<<1|1,mid+1,r); return rs; } int find2(int pos,int l,int r) { if(l>=ql&&r<=qr&&sum[pos]==0) return 0; if(l==r) return l; int mid=(l+r)>>1,rs=0; pd(pos); if(qr>mid) rs=find2(pos<<1|1,mid+1,r); if(!rs&&ql<=mid) rs=find2(pos<<1,l,mid); return rs; } int find3(int pos,int l,int r) { if(l>=ql&&r<=qr&&sum[pos]==0) return 0; if(l==r) return l; int mid=(l+r)>>1,rs=0; pd(pos); if(ql<=mid) rs=find3(pos<<1,l,mid); if(!rs&&qr>mid) rs=find3(pos<<1|1,mid+1,r); return rs; } int main() { freopen("iiidx.in","r",stdin); freopen("iiidx.out","w",stdout); read(n); scanf("%lf",&k); For(i,1,n) read(a[i]); sort(a+1,a+n+1); For(i,1,n) p[i]=a[i]; tot=unique(p+1,p+n+1)-(p+1); int x=1,y; ld[1]=1; For(i,1,n) { if(a[i]!=p[x]) { rd[x]=i-1; ld[++x]=i; } a[i]=x; } rd[x]=n; For(i,1,n) f[i]=(db)i/k,add(f[i],i); s(0); bld(1,1,n); For(i,1,n) { if(f[i]&&f[i]!=f[i-1]) { ql=1; qr=ans[f[i]]; qx=size[f[i]]-1; chge(1,1,n); } ql=ans[f[i]]+1; qr=n; qx=size[i]; x=find1(1,1,n); if(x==0) x=n;else x--; qr=x; x=find2(1,1,n); ql=max(ql,ld[a[x]]); qr=x; x=find3(1,1,n); ans[i]=x; ql=1; qr=x; qx=-size[i]; chge(1,1,n); ql=qr=x; qx=-1; add(1,1,n); } For(i,1,n) printf("%lld ",p[a[ans[i]]]); printf("\n"); return 0; }
update20180506:
cstc试机题,改成了相同的在线段树上缩点,就1A了……
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=1e6+7; ll n,a[maxn],p[maxn],c[maxn],f[maxn],size[maxn],ans[maxn],tot; db k; bool vis[maxn]; char cc;ll ff; template<typename T>void read(T& aa){ aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[maxn],to[maxn],e=0; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; } void s(int pos) { size[pos]=1; for(int y=fir[pos];y;y=nxt[y]) { s(to[y]); size[pos]+=size[to[y]]; } } ll num[4*maxn],laz[4*maxn],ql,qr,qx; void ud(int pos) { num[pos]=min(num[pos<<1],num[pos<<1|1]); } void pd(int pos) { if(!laz[pos]) return; num[pos<<1]+=laz[pos]; num[pos<<1|1]+=laz[pos]; laz[pos<<1]+=laz[pos]; laz[pos<<1|1]+=laz[pos]; laz[pos]=0; } void bld(int pos,int l,int r){ if(l==r) { num[pos]=c[l]; return; } int mid=(l+r)>>1; bld(pos<<1,l,mid); bld(pos<<1|1,mid+1,r); ud(pos); } void chge(int pos,int l,int r) { if(l>=ql&&r<=qr) { num[pos]+=qx; laz[pos]+=qx; return; } int mid=(l+r)>>1; pd(pos); if(ql<=mid) chge(pos<<1,l,mid); if(qr>mid) chge(pos<<1|1,mid+1,r); ud(pos); } int ef(int pos,int l,int r) { if(l==r) { if(num[pos]<qx) return l; return l+1; } int mid=(l+r)>>1; pd(pos); if(num[pos<<1]>=qx) return ef(pos<<1|1,mid+1,r); return ef(pos<<1,l,mid); } void clear(int x) { ql=1; qr=ans[x]; qx=size[x]-1; chge(1,1,tot); vis[x]=0; } int main() { read(n); scanf("%lf",&k); For(i,1,n) read(a[i]); sort(a+1,a+n+1); ll x; For(i,1,n) p[i]=a[i]; tot=unique(p+1,p+n+1)-(p+1); For(i,1,n) { x=lower_bound(p+1,p+tot+1,a[i])-p; ++c[x]; } Rep(i,tot,1) c[i]+=c[i+1]; For(i,1,n) f[i]=floor((db)i/k),add(f[i],i); s(0); bld(1,1,tot); For(i,1,n) { if(vis[f[i]]) clear(f[i]); ql=ans[f[i]]+1; qr=tot; qx=size[i]; ans[i]=ef(1,1,tot)-1; ql=1; qr=ans[i]; qx=-size[i]; chge(1,1,tot); vis[i]=1; } For(i,1,n) printf("%lld ",p[ans[i]]); printf("\n"); return 0; }
D1T3
没看懂题解,但是我会暴力dp+小优化水过
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=1700+7; const ll mod=64123; ll n,k,w,d[maxn],p[maxn],rnk[maxn],dp[maxn][maxn],ans; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[2*maxn],to[2*maxn],e=0; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; to[++e]=x;nxt[e]=fir[y];fir[y]=e; } bool cmp(int x,int y) { return d[x]>d[y]; } ll size[maxn]; void dfs(int pos,int f,int sum) { For(i,0,k) dp[pos][i]=0; if((sum+=size[pos])>k) return; if(size[pos]) dp[pos][1]=1; else dp[pos][0]=1; int y,z; for(y=fir[pos];y;y=nxt[y]) { if((z=to[y])==f) continue; dfs(z,pos,sum); Rep(i,min(size[pos],k),0) if(dp[pos][i]){ Rep(j,min(k-i,size[z]),0) dp[pos][i+j]+=dp[pos][i]*dp[z][j]%mod; } size[pos]+=size[z]; } For(i,0,min(size[pos],k)) dp[pos][i]%=mod; } int main() { freopen("coat.in","r",stdin); freopen("coat.out","w",stdout); read(n); read(k); read(w); For(i,1,n) read(d[i]),p[i]=i; sort(p+1,p+n+1,cmp); For(i,1,n) rnk[p[i]]=i; int x,y; For(i,1,n-1) { read(x); read(y); add(x,y); } For(i,1,n) if(rnk[i]>=k) { For(j,1,rnk[i]) size[p[j]]=1; For(j,rnk[i]+1,n) size[p[j]]=0; dfs(i,0,0); ans+=dp[i][k]*d[i]%mod; } printf("%lld\n",ans%mod); return 0; }
D2T1
题面有点冗长。
我直接EK+bitset了
场上自己做死想优化一下结果优化错了,还忘记了有大样例这个东西。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<bitset> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=400+7,maxm=5000+7,INF=0x3f3f3f3f; int Td,Cd,n,m,S,T,a[maxn][maxn],now,s[maxn],ans1[maxn],ans2[maxn]; bitset<maxn/2> G[maxn],o; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } struct Node{ int x,y,flow,cap; Node(){} Node(int x,int y,int cap):x(x),y(y),cap(cap){flow=0;} }node[2*maxm]; int fir[maxn],nxt[2*maxm],e=1; void add(int x,int y,int z) { node[++e]=Node(x,y,z); nxt[e]=fir[x];fir[x]=e; node[++e]=Node(y,x,0); nxt[e]=fir[y];fir[y]=e; } bool vis[maxn]; bool Expd(int pos) { if(vis[pos]) return 0; if(pos==T) return 1; vis[pos]=1; for(int y=fir[pos];y;y=nxt[y]) { if(node[y].flow>=node[y].cap) continue; if(Expd(node[y].y)) { ++node[y].flow; --node[y^1].flow; return 1; } } return 0; } bool dfs(int pos) { if(vis[pos]) return 0; if(pos==T) return 1; vis[pos]=1; for(int y=fir[pos];y;y=nxt[y]) { if(node[y].flow>=node[y].cap) continue; if(dfs(node[y].y)) return 1; } return 0; } void find(int p) { For(i,1,m) if(G[p][i]) { memset(vis,0,sizeof(vis)); if(dfs(i+n)) G[p+1].set(i); } } void solve() { For(i,1,n) { now=m+1; For(j,1,m) if(G[i][j]) now=min(now,a[i][j]); ans1[i]=now; if(now<=m) { add(S,i,1); For(j,1,m) if(a[i][j]==now) add(i,j+n,1); memset(vis,0,sizeof(vis)); Expd(S); } if(ans1[i]>s[i]) { o.reset(); ans2[i]=i; For(j,1,m) if(a[i][j]<=s[i]) o.set(j); Rep(j,i-1,1) if((o&G[j]).count()) { ans2[i]=i-j; break; } } find(i); } For(i,1,n) printf("%d ",ans1[i]); printf("\n"); For(i,1,n) printf("%d ",ans2[i]); printf("\n"); } void clear() { e=1; For(i,1,n+1) G[i].reset(); memset(fir,0,sizeof(fir)); memset(ans2,0,sizeof(ans2)); } int main() { freopen("mentor.in","r",stdin); freopen("mentor.out","w",stdout); read(Td); read(Cd); int x,y,z; while(Td--) { read(n); read(m); S=n+m+1; T=S+1; clear(); For(i,1,m) { read(x); if(x) add(i+n,T,x),G[1].set(i); } For(i,1,n) For(j,1,m) { read(a[i][j]); if(a[i][j]==0) a[i][j]=INF; } For(i,1,n) read(s[i]); solve(); } return 0; }
D2的T2、T3不会。
场上T2的60分做法,但是来不及打:
题目等价于在树上选k条点不相交的链,使权值和最大。
f[x][k][0/1/2]表示在x的子树中选了k条链,x的度数为0,1,2的最优方案。
T3直接放个Achen博客链接好啦:http://www.cnblogs.com/Achenchen/p/8869906.html
这几天做题觉得有点蒙,每天总是头晕或者头痛或者困,即使中午好生回去睡觉,也怎么都调节不过来。
上周因为考了省选没食欲没胃口,几天没好好吃饭好好睡觉,现在又每天一副这种样子
效率真的好低呀……
跟Achen晚上去跑步的时候,Achen说:
我们如果去NOI,就像是拿着匕首,去参加国际大战,别人一个核弹就炸平一片,人家即使没有核弹也有大炮,没有大炮也有机关枪,而我们赤条条地拿着小匕首往上冲。
如果我们回常规了,就像是把手上唯一的小匕首给扔了,别人虽然也没什么武器,但是天天练得身强体壮,我们又去和这样一大群人肉搏。
这个画面感太强了。
我突然觉得如果当初初一没有被微机课老师骗去"体验了"一下信息竞赛,就不会勾起我的一点点兴趣,然后有这么多烦人事情了。
或者是当时初一的时候我们的班导老师没有强制我们中午不能去上乱七八糟的“中午特长班”,我会从初一学OI到现在,估计也没这么多烦人的事情了。
或者是……
可是人生又不能重来,想这些也是没有用的呀。
而且毕竟还是自己太懒太弱了,又怎么能怨天尤人呢。
我挺赞同Achen博客里面那句话的:
一个人在任意一秒所作出的决定,一个是靠天性,上天注定,一个是他在这一秒之前经历过的所有事--认识的所有人,他们为人处世的方式,他们对他说过的所有话,他读过的所有书,他每一秒看到的风景,每一秒听到的声音,每一秒感受的气息--决定.
我妈曾说,现在看起来不好的决定最后不一定是不好的,现在看起来不好的事情最后不一定是不好的。
有谁能猜到最后的结果呢。