2020牛客暑期多校训练营(第七场)

总结:
这一次做的不好。只出了一道题。
这道题一直在想怎么降低复杂度,后来才想道打表跑一下,把特殊的找出来就行了,然后过了这道题。

B

题意

如今,梦想网格王国正遭受着一场全国性的大流行。幸运的是,宝宝总裁正在与疾病控制中心(CDC)进行有效的合作,他们正在尽最大努力使一切都得到控制。宝宝总裁从他的朋友雷库那里收到了无数个医用口罩,雷库是一个非常富有的亿万富翁。作为疾控中心的主任,你必须正确分配这些口罩。
梦格力王国有2类医院,n家为危重病人提供高级医院,m家为轻度症状患者提供移动舱室医院。
在分配给医院之前,你必须把它们装进盒子里。请注意,为防止污染,不得打开箱子,您只知道这些箱子将分配给高级医院或移动机舱医院。也就是说,应该有一种方法将口罩盒划分为n个口罩的m组,以及将m个口罩分成n组的方法。
您希望盒子的数量是最小的,并请提供一个字典编纂的最大序列的口罩在盒子中。如果存在一个整数i,那么我们说序列a在词典学上比另一个相同长度的b大,例如aj=bj,对于所有的j<i; ai>bi。
有多个测试用例。输入的第一行包含一个整数T(1≤T≤100),表示测试用例的数量。
对于每个测试用例,输入的唯一一行包含两个整数n,m(1≤n,m≤1e4)(代表高级医院和移动客舱医院的数量。
对于每个测试用例,请输出两行。第一行应该在第一行中包含一个整数k,表示最小的盒子数。在第二行中,请输出k个整数,表示字典中最大的序列。

思路

若n<m,调换顺序,保证n>m。每次输出m个m。当m为1时,输出n个1。每次输出后使n=n/gcd(n,m),m=m/gcd(n,m)。

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false),cin.tie(0);
#define ll long long
#define inf 0x3f3f3f3f
const int N=1e5+5;
//set<string>b;
//set<string>::iterator it;
vector<int>a;
int main()
{
    IO;
    int T,n,m,t,i;
	cin>>T;
	while(T--)
	{
		a.clear();
		cin>>n>>m;
		if(n<m) swap(n,m);
		while(m)
		{
			for(i=1;i<=m;i++)
			{
				a.push_back(m);
			}
			t=m;
			m=n-m;
			n=t;
			if(n<m) swap(n,m);
		}
		cout<<a.size()<<endl;
		for(i=0;i<a.size()-1;i++)
		{
			cout<<a[i]<<" ";
		}
		cout<<a[a.size()-1]<<endl;
	}
    return 0; 
}

H

题意

给一个N,K,首先对于所有1,k(1<=k<=K),都是符合要求的,然后所有的符合要求的数的数(n,k),若n+k<N,则(n+k,k)也是好的,若nk<N,则(nk,k)也是好的,求符合要求的数量。

思路

首先可以先写一写,举个栗子,(1,3)。

可以变为(4,3),(3,3)。

现在应该很容易发现,乘法操作已经没用了,因为乘3必然是3的倍数,一定可以通过加3到达,所以可以写成两个不等式。

1+m*k<=N,

m*k<=N,

m表示符合要求的个数,然后暴力枚举k,算出每个m既可,K过大枚举超时,但是我们可以发现k中间有很多的m都相等,呈线性关系,故可用整除分块优化。

代码

#include<iostream>
#define ll long long
using namespace std;
const ll mod=1e9+7;
ll n,k,ans,m,to,now;
int main(){
	scanf("%lld%lld",&n,&k);
	for(ll i=2;i<=k;i++){
		now=i;
		m=n/i;
		if(m==0)break;
		to=min(n/m,k);
		i=to;
		m%=mod;
		to%=mod;
		ans=(ans+m*(to-now+1))%mod;
		//printf("%lld %lld %lld %lld\n",now,to,ans,i);
	}
	for(ll i=2;i<=k;i++){
		now=i;
		m=(n-1)/i;
		if(m==0)break;
		to=min((n-1)/m,k);
		i=to;
		m%=mod;
		to%=mod;
		ans=(ans+m*(to-now+1))%mod;
		//printf("%lld %lld %lld i=%lld\n",now,to,ans,i);
	}
	printf("%lld\n",(ans+k+n-1)%mod);
}

J

题意

一个程序中有26个对象,每个对象有26个成员指针变量,同时还有26个普通的指针变量。给定n条赋值语句,问在以任意顺序执行每条语句无限多次的过程中,每个指针变量可能指向的对象集合。

思路

暴力模拟。
难点在于对题目的理解。比如比如 A = B.f ,B.f 说的是 B 指向的对象(所以要判断B是否为空)的成员变量 f ,而这个成员变量 f 指向了另一个对象,与 B 是无关的,搞个三维数组,然后进行赋值。A.f = B 反过来写就是了。

代码

#include<bits/stdc++.h>
using namespace std;
const long long mod=1e9+7;
long long n,k,ans;
int n, ans[30][30], a[30][30][30];
char s1[222][5], s2[222][5];
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) scanf("%s%s%s", s1[i] + 1, s2[i] + 1, s2[i] + 1);
	int T = n;
	while (T--) {
		for (int i = 1; i <= n; i++) {
			int l1 = strlen(s1[i] + 1);
			int l2 = strlen(s2[i] + 1);
			int c1 = s1[i][1] - 'A';
			int c2 = s2[i][1] - 'A';
			if (l1 == l2) {
				if (s2[i][1] >= 'a') ans[c1][s2[i][1] - 'a'] = 1;
				else for (int j = 0; j < 26; j++) ans[c1][j] |= ans[c2][j];
			}
			else if (l2 >= 3) {
				int c3 = s2[i][3] - 'a';         //c3是成员
				for (int j = 0; j < 26; j++) {   //j是对象
					if (ans[c2][j]) {            //k是第二层对象
						for (int k = 0; k < 26; k++) ans[c1][k] |= a[c3][j][k];
					}
				}
			}
			else {
				int c3 = s1[i][3] - 'a';
				for (int j = 0; j < 26; j++) {
					if (ans[c1][j]) {
						for (int k = 0; k < 26; k++)  a[c3][j][k] |= ans[c2][k];
					}
				}
			}
		}
	}
	for (int i = 0; i < 26; i++) {
		printf("%c: ", 'A' + i);
		for (int j = 0; j < 26; j++) if (ans[i][j]) printf("%c", 'a' + j);
		puts("");
	}
	return 0;  
}



一级目录

题意

思路

代码

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页