牛客小白月赛23

链接:https://ac.nowcoder.com/acm/contest/4784#question
B 最小的n,是n!=p的倍数
从质因数的角度找,找到出现每个质因数的次数的最小的数再取max,假设质因数p出现了m次,p只会出现在p的倍数里面,p出现一次,p*2又出现一次,依次类推,特殊的n^2出现2次, n ^3出现3次…
1还需要特判

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5010;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tir(0);
int n,t;
int get(int x,int cnt)//找x出现cnt次的那个最小值
{
	int i=x,res=0;
	while(1)
	{
		int t=i;
		while(t%x==0) t/=x,res++;
		if(res>=cnt) return i;
		i+=x;
	}
}
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>n;
        if(n==1) 
        {
            cout<<1<<endl;
            continue;
        }
		int k=0,num[1000]={0};
		map<int,int> mp;
		for(int i=2;i<=n/i;i++)
		{
			if(n%i==0) num[k++]=i;
			while(n%i==0)
			{
				mp[i]++;
				n/=i;
			}
		}
		if(n>1) num[k++]=n,mp[n]++;
		int ans=0;
		for(int i=0;i<k;i++)
			ans=max(ans,get(num[i],mp[num[i]]));
		cout<<ans<<endl;
	}
	return 0;
}
 

C 完全图每条边连n-1条边,wtm以为有n条,裂开。那么新出现一个连通块最少需要删n-1条边(将一个点完全割出来),两个就是n-1+n-2(割去一个点后,那个大的连通块剩n-1个点),m个就是
(n-1)+(n-2)+…+(n-m)=m+(n-1+n-m),找到这个规律后就可以二分了。数据范围1e18,会爆ll,可以用int128,也可以用python

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5010;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tir(0);
ll n,t,m;
void print(__int128 x) 
{ 
    if(!x) 
    { 
        puts("0"); 
        return ; 
    } 
    string ret=""; 
    while(x) 
    { 
        ret+=x%10+'0'; 
        x/=10; 
    } 
    reverse(ret.begin(),ret.end()); 
    cout<<ret<<endl; 
}
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        __int128 l=0,r=n;
        while(l<r)//二分新增连通块的数量
        {
            __int128 mid = l+r >> 1;
            if((mid*(2*n-mid-1)/2)>m) r=mid;
            else l=mid+1;
        }
        print(r);//二分出不满足的最小值,答案就是l-1+1
    }
    return 0;
}

E 32为有符号整数的范围是(-2^31, 2 ^31-1)共有2 ^32个数,对于任意一个数a都存在一个数c-b在int范围内,因为会溢出,所以答案就是2 ^32

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010,inf=0x3f3f3f3f;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tir(0);
int n,a[N],l=-inf,r=inf;
int main()
{
	cin>>n;
	cout<<(1ll<<32);
	return 0;
}

G 需要处理每一条边的贡献,然后按贡献从大到小赋值从小到大,每一条边的贡献是有多少路径(u,v)经过这条边,因为是一棵树,所以任意两点间路径唯一,那么贡献是多少呢,就是这条边两边的点数量的乘积,边两边任意两点一定会经过这条边,之前做过类似的可是给忘了…

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,h[N],e[N],ne[N],idx;
vector<long long> ve;
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
int dfs(int u,int pre)
{
	int cnt=0;
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int v=e[i];
		if(v!=pre)
		{
			int res=dfs(v,u);//边(u,v)v那边点的数量
			cnt+=res;
			ve.push_back(1ll*res*(n-res));//n-res是u这边的数量,乘积就是边(u,v)的贡献
		}
	}
    return cnt+1;//加上自身这个点
}
int main()
{
    IOS
	cin>>n;
	memset(h,-1,sizeof h);
	for(int i=1;i<n;i++)
	{
		int a,b;
		cin>>a>>b;
		add(a,b);
		add(b,a);
	}
	dfs(1,-1);
	sort(ve.begin(),ve.end());
	long long ans=0;
	for(int i=0;i<ve.size();i++)
		ans+=1ll*ve[i]*(n-i-1);//按贡献一次递减赋值
	cout<<ans;
	return 0;
 } 

H 每个物品都是以2进制的形式给出的,如果n个物品的和大于等于2 ^30那么一定可以装满。
假设上面是对的,就会有三种情况,29的次数为0,1,2。如果有两个29,那么一定是可以的;如果只有一个29,那么剩余n-1个物品之和一定大于等于2^29,就和上面是类似的了;如果没有29,因为给出的都是二进制,所以可以把n个物品分为两部分,每部分的和都大于等于2 ^29,用这两部分取填满两个2 ^29的背包,又和上面类似了,这是看了题解后我的理解,貌似没问题吧
所以把大的填进去一定可以填满吧

#include<bits/stdc++.h>

using namespace std;
const int N = 1e5+5;
typedef long long ll;
int t;
ll n,m,l,r,mid;
int a[N];
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n;
        ll sum=0;
        for(int i=0;i<n;i++) cin>>a[i],sum+=(1ll<<a[i]);
        if(sum<(1ll<<30)) cout<<"impossible"<<endl;
        else 
        {
        	bool st[N]={0};
        	pair<int,int> b[N];
        	for(int i=0;i<n;i++) b[i]={a[i],i};
        	sort(b,b+n);
        	sum=0;
        	for(int i=n-1;i>=0;i--) 
        	{
        		sum+=(1ll<<b[i].first);
        		st[b[i].second]=1;
        		if(sum==(1ll<<30))
        		{
        			break;
				}
			}
			for(int i=0;i<n;i++) cout<<st[i];
			puts("");
		}
    }    return 0;
}

I 可以找以最大的字符开头的后缀,比较一遍就可以了(数据范围小暴力找每一个子串也是可以的)

#include<iostream>
#include<string>
using namespace std;
string s;
char c=0;
int main()
{
	cin>>s;
	for(int i=0;i<s.size();i++)
		c=max(c,s[i]);
	string st;
	for(int i=0;i<s.size();i++)
		if(s[i]==c)
			st=max(st,s.substr(i));
	cout<<st;
 } 

J

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010,inf=0x3f3f3f3f;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tir(0);
int n,a[N],l=-inf,r=inf;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
        l=max(l,a[i]);
        r=min(r,a[i]);
    }
    cout<<l-r;
    return 0;
}
原文地址:https://www.cnblogs.com/neflibata/p/12871775.html