Niuke Monthly Contest 23

A. Membrane method record

Idea: Note that 1<=n<=5, then we can enumerate the elimination of rows, and then judge whether the elimination of columns can be satisfied. See the code for details.

#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. Factorial

Idea: Perform prime factor decomposition on p, record the occurrence of each prime factor, and then enumerate the smallest factorial required for each prime factor to appear so many times, and then select the largest one.

#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. Complete picture

Idea: For a complete deletion of the first point, n-1 edges are required, and the deletion of the second point requires n-2 edges. Then, for the point with the most deleted m edges, a binary search is used.

#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. Summation on the tree

Idea: Find the number of points x, y on the left and right of each side, and assign the value of the side according to the weight 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. Strange backpacks have been added

Idea: Divide and conquer algorithm, see the code code for details, which is well understood.

#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;
}

 

Guess you like

Origin blog.csdn.net/qq_44132777/article/details/105032358