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