Noip模拟43 2021.8.18
T1 地一体
可以树形$dp$,但考场没写出来,只打了没正确性的贪心水了$30$
然后讲题的时候B哥讲了如何正确的贪心,喜出望外的学习了一下
不难发现
每次士兵都会直接冲到叶子节点
从深的点再返回到另一个比较浅的点肯定是不优的
只有两种情况,士兵从之前的点到新的节点与直接再安排一个士兵冲到这个节点
我们就按这个策略贪心即可
1 #include<bits/stdc++.h> 2 #define int long long 3 #define pb push_back 4 #define mp make_pair 5 #define pii pair<int,int> 6 #define fi first 7 #define se second 8 using namespace std; 9 namespace AE86{ 10 inline int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 14 }inline void write(int x,char opt='\n'){ 15 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 16 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 17 for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 18 }using namespace AE86; 19 20 const int NN=1e5+5,inf=0x3fffffff; 21 int n,ans,pos; 22 int fa[NN],dep[NN],mdp[NN]; 23 bool vis[NN]; 24 vector<pii > e[NN]; 25 26 inline void dfs1(int f,int x){ 27 fa[x]=f; mdp[x]=dep[x]; 28 for(int i=0;i<e[x].size();i++){ 29 int y=e[x][i].se; if(y==f) continue; 30 dep[y]=dep[x]+1; 31 dfs1(x,y); 32 e[x][i].fi=mdp[y]; 33 mdp[x]=max(mdp[x],mdp[y]); 34 } 35 } 36 inline void calc(int x){ 37 if(!pos){ 38 pos=x,ans+=dep[pos]; 39 }else{ 40 if(dep[x]<dep[x]+dep[pos]-2*dep[fa[x]]) pos=x,ans+=dep[x]; 41 else ans+=dep[x]+dep[pos]-2*dep[fa[x]],pos=x; 42 } 43 } 44 inline void dfs(int f,int x){ 45 if(!vis[x]) calc(x),vis[x]=1; 46 for(int i=0;i<e[x].size();i++){ 47 int y=e[x][i].se; if(y==f) continue; 48 dfs(x,y); 49 } 50 } 51 52 namespace WSN{ 53 inline short main(){ 54 n=read(); 55 for(int i=1;i<n;i++){ 56 int x=read(),y=read(); 57 e[x].pb(mp(0,y)); e[y].pb(mp(0,x)); 58 }dfs1(0,1);//for(int i=1;i<=n;i++) cout<<dep[i]<<endl; 59 for(int i=1;i<=n;i++) sort(e[i].begin(),e[i].end()); 60 dfs(0,1); write(ans); 61 return 0; 62 } 63 } 64 signed main(){return WSN::main();}
T2 滴而提
不难发现可以二分出答案
然后考虑在二分的时候如何判断,
宗旨是这样的,如果能更新得动就更新,大神叫这个(迭代最终必将收敛)
一个限制是$K$,如果没有加的次数了就不行了,就收敛就行了
另一个限制是有差值,我们考虑每一个小的$id(i,j)$都必须被填到和周围的格子一样大
这个就是更新,那么如果没有可以更新的就收敛就行
1 #include<bits/stdc++.h> 2 #define int long long 3 #define mp make_pair 4 #define pii pair<int,int> 5 #define fi first 6 #define se second 7 using namespace std; 8 namespace AE86{ 9 inline int read(){ 10 int x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 13 }inline void write(int x,char opt='\n'){ 14 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 15 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 16 for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 17 }using namespace AE86; 18 19 const int NN=1e5+5; 20 int n,m,k,a[NN],tmp[NN]; 21 inline int id(int x,int y){return m*(x-1)+y;} 22 inline bool check(int mid){ 23 int K=k; bool f=1; 24 for(int i=1;i<=n*m;i++) tmp[i]=a[i]; 25 while(K>=0&&f){ 26 f=0; 27 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ 28 if(i-1>=1){ 29 if(tmp[id(i-1,j)]-tmp[id(i,j)]>mid){ f=1; 30 int res=tmp[id(i-1,j)]-tmp[id(i,j)]; 31 tmp[id(i,j)]+=res-mid; K-=res-mid; 32 }if(K<0) return 0; 33 } 34 if(i+1<=n){ 35 if(tmp[id(i+1,j)]-tmp[id(i,j)]>mid){ f=1; 36 int res=tmp[id(i+1,j)]-tmp[id(i,j)]; 37 tmp[id(i,j)]+=res-mid; K-=res-mid; 38 }if(K<0) return 0; 39 } 40 if(j-1>=1){ 41 if(tmp[id(i,j-1)]-tmp[id(i,j)]>mid){ f=1; 42 int res=tmp[id(i,j-1)]-tmp[id(i,j)]; 43 tmp[id(i,j)]+=res-mid; K-=res-mid; 44 }if(K<0) return 0; 45 } 46 if(j+1<=m){ 47 if(tmp[id(i,j+1)]-tmp[id(i,j)]>mid){ f=1; 48 int res=tmp[id(i,j+1)]-tmp[id(i,j)]; 49 tmp[id(i,j)]+=res-mid; K-=res-mid; 50 }if(K<0) return 0; 51 } 52 if(i+1<=n&&j-1>=1){ 53 if(tmp[id(i+1,j-1)]-tmp[id(i,j)]>mid){ f=1; 54 int res=tmp[id(i+1,j-1)]-tmp[id(i,j)]; 55 tmp[id(i,j)]+=res-mid; K-=res-mid; 56 }if(K<0) return 0; 57 } 58 if(i-1>=1&&j+1<=m){ 59 if(tmp[id(i-1,j+1)]-tmp[id(i,j)]>mid){ f=1; 60 int res=tmp[id(i-1,j+1)]-tmp[id(i,j)]; 61 tmp[id(i,j)]+=res-mid; K-=res-mid; 62 }if(K<0) return 0; 63 } 64 } 65 } 66 return 1; 67 } 68 69 namespace WSN{ 70 inline short main(){ 71 n=read();m=read();k=read();int l=0,r=0,ans=l; 72 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[id(i,j)]=read(); 73 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ 74 int dis=0,d1=0,d2=0,d3=0,d4=0,d5=0,d6=0; 75 if(i+1<=n) d1=abs(a[id(i,j)]-a[id(i+1,j)]); 76 if(i-1>=1) d2=abs(a[id(i,j)]-a[id(i-1,j)]); 77 if(j+1<=m) d3=abs(a[id(i,j)]-a[id(i,j+1)]); 78 if(j-1>=1) d4=abs(a[id(i,j)]-a[id(i,j-1)]); 79 if(i+1<=n&&j-1>=1) d5=abs(a[id(i,j)]-a[id(i+1,j-1)]); 80 if(i-1>=1&&j+1<=m) d6=abs(a[id(i,j)]-a[id(i-1,j+1)]); 81 dis=max(d1,max(d2,max(d3,max(d4,max(d5,d6))))); 82 if(r<dis) r=dis; 83 } 84 while(l<=r){ 85 int mid=l+r>>1; 86 if(check(mid)) r=mid-1,ans=mid; 87 else l=mid+1; 88 }write(ans); 89 return 0; 90 } 91 } 92 signed main(){return WSN::main();}
T3 帝三踢
还没改出来,沽沽沽
T4 迪斯鶙
高爸给黄队讲昊爸的做法(集训队的辈份问题是道$NPC$。。。):
可以神仙的把 每个好的序列里面一个数$x$出现次数的平方$k^2$拆成$k^2=\binom{k}{2}*2+k$
然后试图用$dp$表示这个柿子,首先预处理出两个$dp$数组
$f_{i,j}$表示选了$i$个数,最大的值是$j$的方案数
$g_{i,j}$表示前面的一段序列最大值是$j$,后面选了$i$个数的方案数
然后我们就可以把上面的柿子变成
$(\sum_{y>=x} f_{i-1,y}*(g_{n-i,y}+2*(n-i)*g_{n-i-1,y}))+f_{i-1,x-1}*(g_{n-i,x}+2*(n-i-1)*g_{n-i-1,x})$
只能说太神了,先拍再理解了半天才彻底搞明白。。。
最后统计答案的时候处理一个前缀和数组就行
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 15 const int N=3e3+5; 16 int n,p,f[N][N],g[N][N],dp[N][N],ans[N]; 17 18 namespace WSN{ 19 inline short main(){ 20 n=read();p=read();f[0][0]=1; 21 for(int i=0;i<=n;i++) g[0][i]=1; 22 for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) 23 f[i][j]=(f[i-1][j-1]+f[i-1][j]*j%p)%p; 24 for(int i=1;i<=n;i++) for(int j=1;j<=n-i;j++) 25 g[i][j]=(g[i-1][j+1]+g[i-1][j]*j%p)%p; 26 for(int i=1;i<=n;i++){ 27 for(int x=n;x;x--){ 28 dp[i][x]=(dp[i][x+1]+f[i-1][x]*(g[n-i][x]+2*(n-i)%p*g[n-i-1][x]%p)%p)%p; 29 (ans[x]+=dp[i][x]+f[i-1][x-1]*(g[n-i][x]+2*(n-i)%p*g[n-i-1][x]%p)%p)%=p; 30 } 31 }for(int i=1;i<=n;i++) write(ans[i],' '); 32 return 0; 33 } 34 } 35 signed main(){return WSN::main();}