败在了dp上。
100/0/100/0
1792. 教主的花园 (Standard IO)
考虑三种情况:
1:两个点在x轴同侧
这个情况不用考虑,直接计算哈密顿距离即可。
2.两个点在x轴异侧,且两点间有一个出口
这个情况其实也可以直接计算,和1一模一样。
3.两个点在x轴异侧,但是两点间没有出口
这个情况就要找到某个出口,使得它离两点的x轴距离和最近。
最后答案就是距离和。
那么如何求出口位置?
我的写法是用lowbit取点,如果两个点的lowbit一样,说明是第3种情况,否则是第2种,但计算答案3时也要特判一下在两点前面的那个出口。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int read(){ 4 int x=0,f=1; 5 char c=getchar(); 6 while(!isdigit(c)){ 7 if(c=='-') f=-1; 8 c=getchar(); 9 } 10 while(isdigit(c)){ 11 x=(x<<1)+(x<<3)+(c^48); 12 c=getchar(); 13 } 14 return x*f; 15 } 16 const int N=1e5+10; 17 int n,m,x1,y_1,x2,y2; 18 int a[N]; 19 int main(){ 20 21 n=read(); 22 for(int i=1;i<=n;i++) a[i]=read(); 23 sort(a+1,a+n+1); 24 m=read(); 25 for(int i=1;i<=m;i++){ 26 x1=read();y_1=read();x2=read();y2=read(); 27 int pos1=lower_bound(a+1,a+n+1,x1)-a; 28 int pos2=lower_bound(a+1,a+n+1,x2)-a; 29 if((y_1>0&&y2>0)||(y_1<0&&y2<0)){ 30 printf("%d ",abs(y_1-y2)+abs(x1-x2)); 31 } 32 else if(pos1==pos2){ 33 printf("%d ",abs(y2-y_1)+min(abs(x1-a[pos1])+abs(x2-a[pos1]),abs(x1-a[pos1-1])+abs(x2-a[pos1-1]))); 34 } 35 else{ 36 printf("%d ",abs(x2-x1)+abs(y2-y_1)); 37 } 38 } 39 return 0; 40 }
1793. 教主泡嫦娥 (Standard IO)
dp题。
非常烦人的一道题目
不写了。
1794. 保镖排队 (Standard IO)
很有趣的一道题。
题意满足一棵树的关系:
样例的树长这样。
一共有5个节点,那么我们有5!种排列,
分别对每个节点讨论:
点1要放在所有点前面,而将点1放在下方4个节点中,有5种放法。
所以答案只取一种,故要除以5.
对于每个点,我们知道它一定在它的所有子树,和与它同一层的后面的节点包括子树的前面。
比如对于这个图,2要放在圈起来的所有点的前面,因此要除以8。
所以用邻接矩阵建图(用邻接表会打乱遍历的顺序),然后处理当前情况下节点所在的排列大小,把所有答案的逆元乘起来,再乘上总点数的阶乘就能得到答案。
即:
num表示该点和能力比他弱的同层节点子树大小和。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int read(){ 4 int x=0,f=1; 5 char c=getchar(); 6 while(!isdigit(c)){ 7 if(c=='-') f=-1; 8 c=getchar(); 9 } 10 while(isdigit(c)){ 11 x=(x<<1)+(x<<3)+(c^48); 12 c=getchar(); 13 } 14 return x*f; 15 } 16 const int mod=10007; 17 const int N=2000; 18 int t,n,k,ans; 19 int siz[N]; 20 int mul[N]; 21 vector<int> edge[N]; 22 int qp(int x,int y){ 23 int res=x,aa=1; 24 while(y){ 25 if(y&1) aa=(res*aa)%mod; 26 res=(res*res)%mod; 27 y>>=1; 28 } 29 return aa; 30 } 31 void dfs(int u){ 32 siz[u]=1; 33 for(int i=0;i<edge[u].size();i++){ 34 int v=edge[u][i]; 35 dfs(v); 36 siz[u]=siz[u]+siz[v]; 37 } 38 } 39 void dfs2(int u,int now){ 40 for(int i=0;i<edge[u].size();i++){ 41 int v=edge[u][i]; 42 ans=(ans*qp(now,mod-2))%mod; 43 now-=siz[v]; 44 dfs2(v,siz[v]-1); 45 } 46 } 47 int main(){ 48 t=read(); 49 mul[0]=1; 50 for(int i=1;i<=1500;i++)mul[i]=(mul[i-1]*i)%mod; 51 while(t--){ 52 memset(edge,0,sizeof(edge)); 53 n=read(); 54 for(int i=1;i<=n;i++){ 55 k=read(); 56 for(int j=1;j<=k;j++){ 57 edge[i].push_back(read()); 58 } 59 } 60 dfs(1); 61 ans=qp(siz[1],mod-2); 62 dfs2(1,siz[1]-1); 63 printf("%d ",(ans*mul[siz[1]])%mod); 64 } 65 return 0; 66 }
1795. 教主的别墅 (Standard IO)
吐槽一下这个题解:
还是不要用语文来考验我们这些蒟蒻了吧。
我的基本想法是,先求出最小差值,然后贪心就能得到字典序最小的方案,反过来再求一次就能得到字典序最大的方案。
最小差值=S(n)/m,S(n)表示差值前缀和。
考虑一种特殊情况:如果S(n)=0时,要看前缀和中有多少个0,如果0的数量大于分割数m,说明一定可以分成至少m份,每份大小为0,因此答案就是0,否则答案为1,因为至少有两份是将为0的某一份独立拆开的。
最后一遍贪心就可以得到正解了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=5e6+10; 4 inline int read(){ 5 int x=0,f=1; 6 char c=getchar(); 7 while(!isdigit(c)){ 8 if(c=='-') f=-1; 9 c=getchar(); 10 } 11 while(isdigit(c)){ 12 x=(x<<1)+(x<<3)+(c^48); 13 c=getchar(); 14 } 15 return x*f; 16 } 17 int n,m; 18 int sa[N],sb[N]; 19 int c,d,ans1,ans2; 20 inline int gans(int r,int r_){ 21 return r%r_==0?r/r_:(r/r_)+1; 22 } 23 int main(){ 24 n=read(); 25 m=read(); 26 for(int i=1;i<=n;i++){ 27 sa[i]=sb[n-i+1]=getchar()-'0'; 28 } 29 int t1=0,t2=0; 30 for(int i=1;i<=n;i++){ 31 sa[i]=sa[i-1]+(sa[i]==1?1:-1); 32 sb[i]=sb[i-1]+(sb[i]==1?1:-1); 33 if(sa[i]==0) t1++; 34 if(sb[i]==0) t2++; 35 } 36 if(sa[n]==0){ 37 if(t1>=m); 38 else c=1; 39 } 40 else c=gans(abs(sa[n]),m); 41 42 if(sb[n]==0){ 43 if(t2>=m); 44 else d=1; 45 } 46 else d=gans(abs(sb[n]),m); 47 int num=m; 48 int p=0; 49 for(int i=1;i<=n;i++){ 50 if(abs(sa[i]-sa[p])<=c&&gans(abs(sa[n]-sa[i]),num-1)<=c){ 51 printf("%d ",i-p); 52 num--; 53 p=i; 54 if(num==1) break; 55 } 56 } 57 printf("%d ",n-p); 58 num=m; 59 p=0; 60 int cnt=0; 61 for(int i=1;i<=n;i++){ 62 if(abs(sb[i]-sb[p])<=d&&gans(abs(sb[n]-sb[i]),num-1)<=d){ 63 sa[++cnt]=i-p; 64 num--; 65 p=i; 66 if(num==1) break; 67 } 68 } 69 printf("%d ",n-p); 70 for(int i=cnt;i>=1;i--) printf("%d ",sa[i]); 71 return 0; 72 }