牛客月赛23

A.膜法记录

思路:注意到1<=n<=5,那么我们可以枚举行的消除情况,让后再判断列的消除是否可以满足。详情见代码.

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
char s[6][maxn];
int n,m,t,a,b;
int flag,vis[6];
bool C(){
	set<int> c;
	for(int i=1;i<=n;i++){
		if(vis[i]) continue;
		for(int j=0;j<m;j++)
			if(s[i][j]=='*') c.insert(j); 
	}
	return b>=c.size();
}
void dfs(int row, int num){
	if(C()){
		flag=1;return;
	}
	if(row>n||num>=a) return;
	vis[row]=1;
	dfs(row+1,num+1);
	vis[row]=0;
	dfs(row+1,num); 
}


int main(){
	cin>>t;
	while(t--){
		scanf("%d %d %d %d",&n,&m,&a,&b);
		for(int i=1;i<=n;i++) scanf("%s",s[i]);
		flag=0;
		dfs(1,0);
		if(flag) puts("yes");
		else puts("no");
	}
	
	return 0;
}

B.阶乘

思路:对于p进行质因数分解,记录每一个质因数出现的情况,然后枚举每一个质因数出现那么多次数所需要的最小阶乘,然后选择最大的即可。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=3e5+5;
int p[maxn],p_n[maxn],cnt;
int solve(int num, int y){
	int s=0;
	for(int i=1;;i++){
		s++;
		int z=i;
		while(z%y==0){
			s++;z/=y;
		}
		if(s>=num) {
			return y*i; 
		}
	}
}
int main(){
	ll x; 
	int t; scanf("%d",&t);
	while(t--){
		cnt=0;
		scanf("%lld",&x);
		
		if(x==1) {
			printf("1\n"); continue;
		}
                //质因数分解
		for(int i=2;i*i<=x;i++){
			if(x%i==0){
				p[++cnt]=i;p_n[cnt]=0;
				while(x%i==0){
					p_n[cnt]++;x/=i;
				}
			}
		}
		if(x>1) p[++cnt]=x,p_n[cnt]=1;

                //枚举每一个质因数
		int ans=0;
		for(int i=1;i<=cnt;i++){
			//cout<<p_n[i]<<" "<<p[i]<<endl;
			ans=max(ans,solve(p_n[i],p[i]));
		}
		cout<<ans<<endl;
	}
	
	return 0;
}

C.完全图

思路:对于一个完全删除第一个点需要n-1条边,删除第二个点需要n-2条边,那么对于删除m条边最多删除的点,用二分查找。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m;
int main(){
	int t; scanf("%d",&t);
	while(t--){
		scanf("%lld%lld",&n,&m);
		ll l=0,r=n-1;
		while(r>l){
			ll mid=(l+r+1)>>1;
			if(2*n-mid-1<=2*m/mid) l=mid;
			else r=mid-1;
		}
                //删除l个点,形成l+1个连通分量
		cout<<l+1<<endl;
	}
}

G.树上求和

思路:求每一条边左右的点的数量x,y,根据权值x*y进行分配边的值。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
int n;
vector<int> e[maxn];
ll a[maxn],t;
ll dfs(int u, int fa){
	ll sum=1;
	for(int i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(v!=fa){ //使其仅向一侧遍历
			sum+=dfs(v,u);
		}
	}
	a[t++]=sum*(n-sum);
	return sum;
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int u,v; scanf("%d %d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1,-1);
	sort(a,a+t);
	ll ans=0,k=1;
	for(int i=t-1;i>=0;i--){
		ans+=k*a[i];k++;
	}
	cout<<ans<<endl;
	return 0;
}

H.奇怪的背包增加加了

思路:分治算法,详情见代码代码,很好理解的。

#include <bits/stdc++.h>
using namespace std;
int a[33],b[33],t;
int n;
int c[100005];

int solve(int x,int s){
	if(x==1&&a[x]<s) return 0;
	if(a[x]>=s){
		a[x]-=s;
		return 1;
	} else{
		s-=a[x];
		a[x]=0;
	} 
	
	return solve(x-1,s*2);
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		for(int i=0;i<n;i++){
			scanf("%d",c+i);
			b[c[i]]++;a[c[i]]++;
		}
		if(solve(30,1)){
			for(int i=0;i<n;i++){
				if(b[c[i]]>a[c[i]]){
					printf("1"); a[c[i]]++;
				} else printf("0");
			}
			printf("\n");
		}
		else puts("impossible");
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44132777/article/details/105032358