8.8模拟赛总结

T1:

image

直接秒,维护可删除并查集即可

好像在赛场上犯了一个很唐的问题(好像是忘输入了?),然后就花了1h中途输入法还坏了,运气非常不好

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2005,M=4e6+5,inf=1e9;
int n,m,ans1,ans=inf;
int fa[M],siz[M],a[N][N];
char s[N];
struct delate{
	int x,y,sz;
};
vector<delate>del;
int id(int i,int j){
	if(i>n||i<1||j>m||j<1)  return 0;
	return (i-1)*m+j;
}
void init(){
	for(int i=1;i<=n*m;i++)  fa[i]=i,siz[i]=1;
}
int find(int x){
	if(x==fa[x])  return x;
	return find(fa[x]);
} 
void merge(int x,int y,int op){
	int xx=find(x),yy=find(y);
	if(xx==yy)  return;
	if(siz[xx]>siz[yy])  swap(xx,yy);
	if(op)  del.push_back({xx,yy,siz[yy]});
	siz[yy]+=siz[xx];
	fa[xx]=yy;
	return;
}
int main(){
	freopen("plague.in","r",stdin);
	freopen("plague.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++){
			if(s[j]=='0')  a[i][j]=0;
			else  a[i][j]=1,ans1++;
		} 
	}
	init();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]){
				if(id(i-1,j)&&a[i-1][j])  merge(id(i-1,j),id(i,j),0);
				if(id(i,j-1)&&a[i][j-1])  merge(id(i,j-1),id(i,j),0);
				if(id(i+1,j)&&a[i+1][j])  merge(id(i+1,j),id(i,j),0);
				if(id(i,j+1)&&a[i][j+1])  merge(id(i,j+1),id(i,j),0);
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(!a[i][j]){
				if(id(i-1,j)&&a[i-1][j])  merge(id(i-1,j),id(i,j),1);
				if(id(i,j-1)&&a[i][j-1])  merge(id(i,j-1),id(i,j),1);
				if(id(i+1,j)&&a[i+1][j])  merge(id(i+1,j),id(i,j),1);
				if(id(i,j+1)&&a[i][j+1])  merge(id(i,j+1),id(i,j),1);
				ans=min(ans,siz[find(id(i,j))]);
//				printf("%d %d %d %d %d\n",i,j,id(i,j),find(id(i,j)),siz[find(id(i,j))]);
			}
			while(!del.empty()){
				delate g=del.back();
				del.pop_back();
//				printf("del %d %d %d\n",g.x,g.y,g.sz);
				fa[g.x]=g.x;
				siz[g.y]=g.sz;
			}
		}
	}
	printf("%.9lf",(double)ans/(ans1+1));
}

T2:

image

T2看到了,直接就想到了找中心肯定是不好找的,所以应当从两边往中间跳,然后应该是又过了20min,观察到数据范围 1e6,可以预处理每个位置的前一个和后一个图腾的位置

其实再加一个记忆化搜索就是正解了,考虑到

\(\sum_{i=1}^n n/i=O(n\log n)\)

证明:

image

因为上式小于下式所以得证

所以我们加上一个记忆化搜索就可以过了此题

我考场上竟然觉得这个是暴力。。。

然后白白又想了一个小时。。。

最后也没加记忆化,但还是侥幸过了此题

用时 > 1h30min

trick+1

T3:

考场上打了10pts暴力

发现自己的快速幂不会了。。。

然后花了20分钟终于把快速幂调过了。。。

但是赛后发现挂了

image

原因是什么呢?

原因是考虑道它这是实数,我们考虑的不是端点之间的整数点,而是两个端点之间的段数

对于实数的思想:

我们显然不能枚举每一种情况,因为实数的数量是无穷的

所以我们可以规定一个大范围,往上加条件,然后满足某个条件的概率就可以求出来

大范围:假如我们有 \(n\)\([0,m]\) 的随机实变量 \(b_1∼b_n\)

\(l_i^′=max(l_i,a_i−d),r_i^′=min(r_i,a_i+d)\)

设下述条件满足的概率是 \(P\)

对于所有 \(i,b_i≤b_i+1\)\(b_i∈[l_i,r_i]\)

设下述条件满足的概率是 \(Q\)

对于所有 \(i,b_i≤b_i+1\)\(b_i∈[l′_i,r′_i]\)

那么 \(Q/P\) 应当等于原问题的答案

注意到 \(P\)\(Q\) 形式相同,现在分析如何计算 \(P\)

非常巧妙的trick

注意到 \(b_i≤b_i+1\) 是相对条件(不好满足),\(b_i∈[l_i,l_i]\) 是绝对条件(好满足)

所以我们应当遵循绝对条件,在绝对条件的各种约束下,计算满足相对条件的概率

具体计算如下

image

Q1:两个数取相同情况怎么办?

A1:实数有无穷个,相同概率为0

注意:在实际计算中不用算 \(m^x\) 这一项,因为 \(Q/P\) 消掉了

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1005,mod=1e9+7,M=63;
int st[M+5],f[N*2],g[N*2],l[N],r[N],dp[N*2][N],a[N];
int n,m,ans1,ans2,d;
int qp(int x,int p){
	int cnt=1;
	st[0]=x;
	for(int i=1;i<=M;i++){
		st[i]=st[i-1]*st[i-1]%mod;
	}
	for(int i=0;i<=M;i++){
		if(1&(p>>i))  cnt=cnt*st[i]%mod;
	}
	return cnt;
}
int inv(int x){
	return qp(x,mod-2);
}
void init(){
	f[0]=1;
	for(int i=1;i<=N-2;i++){
		f[i]=f[i-1]*inv(i)%mod;
//		printf("f=%lld\n",f[i]);
	}
}
void update(int &x,int nx){
	x=(x+nx)%mod;
}
int query(){
	memset(g,0,sizeof(g));
	memset(dp,0,sizeof(dp));
	m=0;
	for(int i=1;i<=n;i++){
		g[++m]=l[i],g[++m]=r[i]; 
	}
	sort(g+1,g+1+m);
	m=unique(g+1,g+1+m)-g-1;
	dp[1][0]=1;
	for(int x=1;x<m;x++){
		for(int i=0;i<=n;i++){
			update(dp[x+1][i],dp[x][i]);
			for(int j=i+1,w=(g[x+1]-g[x]);j<=n&&(l[j]<=g[x]&&g[x+1]<=r[j]);j++,w=w*(g[x+1]-g[x])%mod){
//				printf("%lld %lld %lld %lld %lld\n",x,i,j,dp[x-1][i],f[j-i]);
				update(dp[x+1][j],dp[x][i]*w%mod*f[j-i]%mod);
			}
		}
	}
//	for(int x=0;x<m;x++){
//		for(int i=0;i<=n;i++){
//			printf("%lld ",dp[x][i]);
//		}
//		printf("\n"); 
//	}
	return dp[m][n];
}
signed main(){
	freopen("wizard.in","r",stdin);
	freopen("wizard.out","w",stdout);
	scanf("%lld%lld",&n,&d);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&l[i],&r[i]);
	}
	init();
	ans1=query();
	ans2=-1;
	for(int i=1;i<=n;i++){
		l[i]=max(l[i],a[i]-d);
		r[i]=min(r[i],a[i]+d);
		if(l[i]>=r[i])  ans2=0;
	}
	if(ans2==-1)  ans2=query();
	printf("%lld",ans2*inv(ans1)%mod);
}

T4:

image

image

赛时背包忘了,遂放弃思考。。。

老师讲的正解正确性证明没听懂,但pjy大菊赛场上切了这道题,他的做法可能会被hack,但是看上去真的很正确,遂采用他的方法

考虑我们如果找到一条路径后,就给他转化成了一个序列上的问题

因为值域在1e9无法背包,考虑贪心,先选性价比 \(w/c\) 高的物品,但是正确性?

如果只有容量为5的背包,当w相同时,选一个c=4的不如c=2,3的更优

又考虑到c<=5,所以我们是不是可以新进行贪心,预留25格容量进行背包?

把因为n<=30,看起来就不像是什么正经的复杂度,遂考虑爆搜路径+剪枝

剪枝就是我们希望路径尽可能地长,所以如果一条边的起点不通过这条路径也能到达终点,就把它剪掉

代码:(注释地方都是调试中出现的问题)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=35;
int n,m,r,ans;
int vis[N],e[N][N],dp[N];
struct dot{
	int c,w,k;
}a[N];
vector<int>b[N];
vector<dot>S,G;
bool arr(int u,int v){
	for(int i=1;i<=n;i++)  vis[i]=0;
	queue<int>q;
	q.push(u);
	while(!q.empty()){
		int i=q.front();
		q.pop();
		for(int j=1;j<=n;j++){
			if(e[i][j]&&!vis[j]){
				vis[j]=1;
				q.push(j);
			}
		}
	}
	if(vis[v])  return 0;
	return 1;
} 
bool cmp(dot i,dot j){
	return i.w*j.c>j.w*i.c;
}
void solve(){
	int cnt=0;
	G=S;
	sort(G.begin(),G.end(),cmp); 
	int mon=r,d=0,num=G.size()-1;
	while(mon>25ll&&d<=num){
		int k=min((mon-25)/G[d].c,G[d].k);
		mon-=k*G[d].c;
		cnt+=k*G[d].w;
		if(G[d].k==k)  d++;
		else{
			G[d].k-=k;
			break;
		}
	}
	memset(dp,0,sizeof(dp));
//	printf("d %lld\n",mon);
	for(int i=d;i<=num;i++){
//		printf("%lld %lld %lld\n",G[i].c,G[i].w,G[i].k);
		for(int j=1;j<=min(G[i].k,mon);j++){
			for(int g=mon;g>=G[i].c;g--){
				dp[g]=max(dp[g],dp[g-G[i].c]+G[i].w);
//				printf("%lld ",dp[g]);
			}
//			printf("\n");
		}
	}
	if(d<=num)  cnt+=dp[mon];//万一mon很大就会RE 
	ans=max(cnt,ans);
}
void dfs(int u){
	S.push_back(a[u]);
	if(u==n){
		solve();
		S.pop_back();//一定要记得在return 前也要加 
		return;
	}
	for(int v:b[u]){
		dfs(v);
	}
	S.pop_back();
}
signed main(){
	freopen("rider.in","r",stdin);
	freopen("rider.out","w",stdout);
	scanf("%lld%lld%lld",&n,&m,&r);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld%lld",&a[i].c,&a[i].w,&a[i].k); 
	}
	for(int i=1;i<=m;i++){
		int u,v;
		scanf("%lld%lld",&u,&v);
		e[u][v]=1;
	} 
	for(int u=1;u<=n;u++){
		for(int v=1;v<=n;v++){
			if(!e[u][v])  continue;
			e[u][v]=0;
			if(arr(u,v)){
				e[u][v]=1;
				b[u].push_back(v);
			}  
		}
	}	
//	for(int i=1;i<=n;i++){
//		for(int j:b[i]){
//			printf("%d %d\n",i,j);
//		}
//	} 
	dfs(1);
	if(!ans)  ans=-1;
	printf("%lld\n",ans);
}
posted @ 2025-08-09 20:41  daydreamer_zcxnb  阅读(34)  评论(0)    收藏  举报