8.18题解
T1[BZOJ1856]
卡特兰数,和网格那道题相似度$99.99{\%}$
思路一
思路二
1 #include<iostream> 2 #include<cstdio> 3 #define maxn 1001000 4 #define ll long long 5 using namespace std; 6 const long long mod=20100403; 7 int n,m; 8 ll ans; 9 ll jc[maxn*2],ny[maxn*2]; 10 ll ksm(ll a,ll b) 11 { 12 ll ans=1; a=a%mod; 13 while(b) 14 { 15 if(b&1) ans=(ans*a)%mod; 16 b=b>>1; a=(a*a)%mod; 17 } 18 return ans; 19 } 20 ll C(int x,int y) 21 { 22 return ((jc[x]*ny[y])%mod*ny[x-y])%mod; 23 } 24 int main() 25 { 26 scanf("%d%d",&n,&m); 27 jc[0]=1; 28 for(int i=1;i<=2*n;++i) jc[i]=(jc[i-1]*i)%mod; 29 ny[2*n]=ksm(jc[2*n],mod-2); 30 for(int i=2*n;i>=1;--i) ny[i-1]=(ny[i]*i)%mod; 31 ans=(C(n+m,n)-C(n+m,m-1)+mod)%mod; 32 printf("%lld\n",ans); 33 return 0; 34 }
T2[BZOJ3441]
暴力模拟50分,优化暴力95分,然而考场上我打了个二分,考后迅速hack掉自己,考场没想到
正解用数据结构优化了模拟的过程
设$cnt[i]$代表第$i$个水缸最多可以下降几次,按$cnt$为关键字排序,$cnt$小的可以被喝的次数,对于$cnt$大的一定满足,所以答案可以直接转移,我们接下来需要做的是计算每个水缸对答案的贡献,我们枚举每一个水缸,尽量让每一个水缸剩余的水尽量少,先看这个水缸支持跳几遍n的水缸,然后用树状数组维护区间内可用水缸个数,二分查找当前水缸支持跳跃的最远的水缸继续转移下去即可
不懂可以去这个大佬那里膜拜一下
#include<algorithm> #include<iostream> #include<cstdio> #define maxn 100100 using namespace std; struct node{ int cnt,pos; }b[maxn]; int n,m,x,sum/*喝几次*/,tot/*喝几趟*/,poss/*乌鸦所在的位置*/; int w[maxn],a[maxn],c[maxn]/*维护区间可用水缸个数*/; bool cmp(const node &a,const node &b) { return a.cnt<b.cnt; } int lowbit(int x) { return x&(-x); } void add(int po,int w) { for(;po<=n;po+=lowbit(po)) c[po]+=w; } int getsum(int po) { int ans=0; for(;po;po-=lowbit(po)) ans+=c[po]; return ans; } int ef(int w) { int l=1,r=n,ANS=l; while(l<=r) { int mid=(l+r)>>1; int Ans=getsum(mid)-getsum(poss); if(Ans>w) r=mid-1; else {l=mid+1; ANS=mid;} } return ANS; } int main() { scanf("%d%d%d",&n,&m,&x); for(int i=1;i<=n;++i) scanf("%d",&w[i]); for(int i=1;i<=n;++i) { scanf("%d",&a[i]); b[i].cnt=(x-w[i])/a[i]+1;//计算当前水缸最多可以被喝几次 b[i].pos=i; add(i,1); } sort(b+1,b+n+1,cmp); for(int i=1;i<=n;++i) { //把不能继续被喝的直接搞掉,不做贡献 if(b[i].cnt<sum) {add(b[i].pos,-1); continue;} //一个水缸最多能被喝几趟,之后就不能再喝一整趟 //对于前面乌鸦停在了中间某个位置上,要先把剩余的水缸喝过去 while(tot<m&&b[i].cnt>getsum(n)-getsum(poss)+sum) //当前水缸中剩下的水,在喝完前边喝过的次数之后,能否撑到后面的水缸都再喝一次 //由于按可喝次数降序排列,前面的可以喝这么多次,那后面的有一定可以喝这么多次 {sum+=getsum(n)-getsum(poss); tot++; poss=0;} if(tot>=m) break; poss=ef(b[i].cnt-sum);//最多喝到第几个水缸就把当前水缸减没了,乌鸦现在停留在这个位置上 //前面已经求得该水缸被喝b[i].cnt次是合法的,又由于排序,第i个合法,那么第i+1个一定是合法的 sum=b[i].cnt;//直接继承,从poss开始,继续向后喝 add(b[i].pos,-1);//当前水缸通过贪心,已经被喝到不能继续喝,直接去掉 } printf("%d\n",sum); return 0; }
T3[BZOJ1924]
和轰炸那题一个思路,建图,tarjan缩点,拓扑即可,建图的时候只给藏宝宫室之间简便即可,和空宫室建边显然没用
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 #include<stack> 6 #include<queue> 7 #define maxn 100100 8 using namespace std; 9 struct node{ 10 int x,y,opt,pos; 11 }; 12 int n,r,c,js,tot,cnt,j,ans; 13 int dfn[maxn],low[maxn],pd[maxn],ss[maxn],du[maxn]; 14 vector <node> cb; 15 vector <node> h[maxn]; 16 vector <node> l[maxn]; 17 vector <int> so[maxn]; 18 vector <int> sh[maxn]; 19 vector <int> son[maxn]; 20 stack <int> s; 21 queue <int> q; 22 void tarjan(int x) 23 { 24 dfn[x]=low[x]=++tot; pd[x]=1; s.push(x); 25 for(int i=0;i<son[x].size();++i) 26 { 27 int ls=son[x][i]; 28 if(!dfn[ls]) {tarjan(ls); low[x]=min(low[x],low[ls]);} 29 else if(pd[ls]) low[x]=min(low[x],dfn[ls]); 30 } 31 if(low[x]==dfn[x]) 32 { 33 int y; cnt++; 34 do 35 { 36 y=s.top(); s.pop(); 37 pd[y]=0; ss[y]=cnt; sh[cnt].push_back(y); 38 } 39 while(y!=x); 40 } 41 } 42 int main() 43 { 44 scanf("%d%d%d",&n,&r,&c); 45 for(int i=1;i<=n;++i) 46 { 47 int o,p,q; scanf("%d%d%d",&o,&p,&q); 48 cb.push_back((node){o,p,q,i}); 49 h[o].push_back((node){o,p,q,i}); 50 l[p].push_back((node){o,p,q,i}); 51 } 52 for(int i=0;i<cb.size();++i) 53 { 54 node ls=cb[i]; 55 if(ls.opt==1) 56 for(int j=0;j<h[ls.x].size();++j) son[ls.pos].push_back(h[ls.x][j].pos); 57 if(ls.opt==2) 58 for(int j=0;j<l[ls.y].size();++j) son[ls.pos].push_back(l[ls.y][j].pos); 59 if(ls.opt==3) 60 { 61 /*for(int j=0;j<cb.size();++j) 62 { 63 node ls1=cb[j]; 64 if(ls1.x==ls.x&&ls1.y==ls.y+1) son[ls.pos].push_back(ls1.pos); 65 else if(ls1.x==ls.x&&ls1.y==ls.y-1) son[ls.pos].push_back(ls1.pos); 66 else if(ls1.x==ls.x+1&&ls1.y==ls.y) son[ls.pos].push_back(ls1.pos); 67 else if(ls1.x==ls.x-1&&ls1.y==ls.y) son[ls.pos].push_back(ls1.pos); 68 else if(ls1.x==ls.x-1&&ls1.y==ls.y-1) son[ls.pos].push_back(ls1.pos); 69 else if(ls1.x==ls.x-1&&ls1.y==ls.y+1) son[ls.pos].push_back(ls1.pos); 70 else if(ls1.x==ls.x+1&&ls1.y==ls.y-1) son[ls.pos].push_back(ls1.pos); 71 else if(ls1.x==ls.x+1&&ls1.y==ls.y+1) son[ls.pos].push_back(ls1.pos); 72 }*/ 73 for(int j=0;j<h[ls.x-1].size();++j) 74 if(h[ls.x-1][j].y==ls.y||h[ls.x-1][j].y==ls.y-1||h[ls.x-1][j].y==ls.y+1) 75 son[ls.pos].push_back(h[ls.x-1][j].pos); 76 for(int j=0;j<h[ls.x+1].size();++j) 77 if(h[ls.x+1][j].y==ls.y||h[ls.x+1][j].y==ls.y-1||h[ls.x+1][j].y==ls.y+1) 78 son[ls.pos].push_back(h[ls.x+1][j].pos); 79 for(int j=0;j<h[ls.x].size();++j) 80 if(h[ls.x][j].y==ls.y-1||h[ls.x][j].y==ls.y+1) 81 son[ls.pos].push_back(h[ls.x][j].pos); 82 } 83 } 84 for(int i=1;i<=n;++i) 85 if(!dfn[i]) tarjan(i); 86 for(int i=1;i<=n;++i) 87 for(int j=0;j<son[i].size();++j) 88 { 89 int ls=son[i][j]; 90 if(ss[i]!=ss[ls]) 91 {so[ss[i]].push_back(ss[ls]); du[ss[ls]]++;} 92 } 93 memset(pd,0,sizeof(pd)); 94 for(int i=1;i<=cnt;++i) 95 if(!du[i]) {q.push(i); pd[i]=sh[i].size();} 96 while(q.size()) 97 { 98 int ls=q.front(); q.pop(); 99 ans=max(ans,pd[ls]); 100 for(int i=0;i<so[ls].size();++i) 101 { 102 int lss=so[ls][i]; du[lss]--; 103 int js=sh[lss].size(); 104 pd[lss]=max(js+pd[ls],pd[lss]); 105 if(du[lss]==0) q.push(lss); 106 ans=max(ans,pd[lss]); 107 } 108 } 109 printf("%d\n",ans); 110 return 0; 111 }