BDH
B. Mask Allocation
题意
题目读了半天才读懂....
有n*m个口罩,把他们装到盒子里,然后必须满足既可以把这些口罩分成n组,一组m个;也可以将它们分成m组,一组n个。要求分的组数最少,并且字典序最大。
题解
比赛的时候没敢写,没造出来样例,怕演了队友...
就是类似于gcd一样的dfs,如果 n<m 的话,交换n和m,每次取n/m*m个m,然后剩下的n%m个m就继续往下递归,直到口罩分配完。这样写代码有点不美观,可以直接变成类似于辗转相除法一样的。具体看代码。
代码
#include<bits/stdc++.h>
using namespace std;
priority_queue<int>ans;
void dfs(int n,int m)
{
if(n==0||m==0) return;
if(n<m) swap(n,m);
for(int i=0;i<m;i++) ans.push(m);
dfs(m,n-m);
}
int main()
{
int n,m;
int t;
cin>>t;
while(t--){
cin>>n>>m;
dfs(n,m);
cout<<ans.size()<<endl;
while(!ans.empty()){
cout<<ans.top()<<' ';
ans.pop();
}
cout<<endl;
}
return 0;
}
D. Fake News
题意
给定一个n,判断是不是一个完全平方数,是的话输出"Fake news!",否则输出“Nobody knows it better than me!”。
题解
当时的做法是打表,然后大胆猜测只有1和24的时候是Fake news,交一发发现是对的。emmm,具体证明看:https://www.zhihu.com/question/363661682
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
ll n;
scanf("%lld",&n);
if(n == 1 || n == 24)
printf("Fake news!\n");
else
printf("Nobody knows it better than me!\n");
}
return 0;
} H. Dividing
题意
正整数二元组传奇元组 (n, k) 是这样定义的
• (1, k) 总是 传奇元组
• 若 (n, k) 是 传奇元组, 那么 (n + k, k) 也是
• 若 (n, k) 是 传奇元组, 那么 (nk, k) 也是
• 统计有多少个 传奇元组 (n, k) 满足 1 ≤ n ≤ N, 1 ≤ k ≤ K, 其中 N 和 K 是不超过 1012 的整数
题解
队友巨巨场上推出了一个公式:N + ( N / 2 + ……+ N /K ) *2 + N%2!=0 + ……+ N%K!=0。造了几个样例发现这个式子是对的,然后数论选手开始工作.gif 。
思路是当k是1的时候,有N个是可行解;当k不是1的时候,那么必须要n%k==0或者(n-1)%k==0,在N内以k为循环的每个循环中会有两个可行解,第一个解%k==1,第二个解%k==0,所以当N%k!=0的时候,n/k个循环外还会有一个第一个解,所以解的个数要加一个。
出题人的题解想法:如果(n,k)是传奇元组,那么一定有下面三个条件中的一个
- n==1
- n%k==0
- (n-1)%k==0
做法
• 先讨论 n%k==0 的情况, 不妨设 n=xk, 那么, x 和 k 中总有一个数字不超过 106 , 枚举 x 和 k 中较小的一个即可, 另一个的个数可以直接通过计算获取
• 对于 (n-1)%k==0 的情况也是同样的
• 对于 n=1 的情况, 直接统计即可
代码
按照队友巨巨公式的代码
#include <cmath>
#include <vector>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
vector<ll> v;
int main() {
ll n, k;
scanf("%lld%lld", &n, &k);
ll ans = n;
for (ll l = 2, r; l <= k; l = r + 1) {
if (n/l == 0)break;
r = min(n/(n/l), k);
ans = (ans + ((r-l+1) * (n / l)) * 2LL % mod) % mod;
}
ll kk = sqrt(n);
for (ll i = 1; i <= kk; ++i) {
if (n % i == 0) {
v.push_back(i);
if (i == (n/i));
else {
v.push_back(n/i);
}
}
}
ans = (ans + k) % mod;
for (int i = 0; i < (int)v.size(); ++i) {
if (k >= v[i]) ans--;
}
ans = (ans % mod + mod) % mod;
printf("%lld\n", ans % mod);
return 0;
} 按照出题人思路的代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
int main()
{
ll n,k;
cin>>n>>k;
ll ans=(n+k-1)%mod;
for(ll i=2;i<=min(n,k);i++){
ll j=min(n/(n/i),k);
ans=(ans+(j-i+1)%mod*(n/i)%mod)%mod;
i=j;
}
n--;
for(ll i=2;i<=min(n,k);i++){
ll j=min(n/(n/i),k);
ans=(ans+(j-i+1)%mod*(n/i)%mod)%mod;
i=j;
}
cout<<ans<<endl;
return 0;
} 
京公网安备 11010502036488号