A 切蛋糕
大意:
现在有一个蛋糕,需要分给k个人,每次操作可以将一个蛋糕分为2份,还可以选择一些蛋糕打包为一份,最后需要打包出k份,使得每一份的蛋糕量为1/k,误差不大于1e-10,全部操作需要在6000步内完成‘
k保证不大于2e10
思路:
直接将所有的蛋糕分为1/1e-10,这样需要的操作数为2e11-1,也就是2047次,然后打包出k份,操作次数不超过2e10,总体不超过2047+1024次,小于6000次
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 2e5 + 10;
int n, m, T;
int two[15];
void init()
{
two[0] = 1;
for (int i = 1; i < 13; i++)
{
two[i] = 2 * two[i - 1];
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
init();
cout << two[11] - 1 + n << endl;
int cnt = 0;
for (int i = 0; i <= 10; i++)
{
for (int j = 0; j < two[i]; j++)
{
cout << 1 << " " << i << endl;
}
}
double ans = 1.0 / n
int num = ans / (1.0 / two[11]);
for (int i = 0; i < n; i++)
{
cout << 2 << " " << num;
for (int j = 0; j < num; j++)
cout << " " << 11;
cout << endl;
}
return 0;
}
B 小宝的幸运数组
大意:
给出一个长度为n的数组,要求找到一个区间使得区间和为k的倍数,如果有的话输出最长的区间长度,否则输出-1
思路:
记录前缀和出现的最早位置,然后相减即可,需要每次都模k,这样保证区间和是k的倍数
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n, r;
LL sum[N], a[N], k;
map<LL, int> mp;
int main() {
cin >> t;
while (t--) {
cin >> n >> k;
mp.clear();
int res = -1;
mp[0] = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum[i] = (sum[i - 1] + a[i] % k) % k;
if(mp.count(sum[i])){
res = max(res, i - mp[sum[i]]);
}
else
mp[sum[i]] = i;
}
cout << res << endl;
}
return 0;
}
C 上进的凡凡
大意:
给出长度为n的数组,求出其中不下降子数组的数量
思路:
直接扫一遍,如果遇到长度为k的不下降子数组,那么答案应该加上1到k的累加和
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int const N = 2e5 + 10;
LL n, m, T;
LL a[N];
LL jie[N+10];
void init(){
jie[0]=jie[1]=1;
for(int i=2;i<=N;i++){
jie[i]=jie[i-1]+i;
}
}
int main() {
cin>>n;
init();
for(int i=1;i<=n;i++){
cin>>a[i];
}
LL num=0;
LL ans=0;
for(int i=1;i<=n;i++){
if(a[i]>=a[i-1]) num++;
else{
ans+=jie[num];
num=1;
}
}
ans+=jie[num];
cout<<ans<<endl;
return 0;
}
D Seek the Joker I
大意:
一共n个数的堆,从上到下开始取,每次最少取1个,最多取k个,取到最后一个的为输
先手赢输出yo xi no forever!
后手赢输出ma la se mi no.1!
思路:
巴什博弈裸题
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n, k;
int main(){
cin >> t;
while(t--){
cin >> n >> k;
if (n % (k + 1) == 1) cout << "ma la se mi no.1!" << endl;
else
cout << "yo xi no forever!" << endl;
}
return 0;
}
E Seek the Joker II
大意:
一个n个数的堆,每次可以从上面取任意个数,或者从下面取任意个数,或者同时从上面和下面取相同多个数,取到原来第x个的为输
先手赢输出yo xi no forever!
后手赢输出ma la se mi no.1!
思路:
威佐夫博弈裸题
#include <bits/stdc++.h>
using namespace std;
int T;
int main() {
int n1,n2,temp, n, x;
cin >> T;
while(T--) {
cin >> n >> x;
n1 = x - 1, n2 = n - n1 - 1;
if(n1>n2) swap(n1,n2);
temp=floor((n2-n1)*(1+sqrt(5.0))/2.0);
if(temp==n1) cout<<"ma la se mi no.1!"<<endl;
else cout<<"yo xi no forever!"<<endl;
}
return 0;
}
F 成绩查询ing
大意:
给出n个人的学号、成绩、性别、姓名
然后是m次查询,如果输入的是成绩,则输出全部的成绩为这个成绩的学生的姓名(按字典序)
如果查询的是姓名,则输出学生的成绩
思路:
直接模拟即可,但是由于n和m比较大,直接查询会超时,但是由于成绩的范围都是1到100,所以可以首先预处理出1到100分的答案,查询的时候直接输出即可
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
int const N = 1e5 + 10;
int n, m;
unordered_map<string,PIII> mp;
unordered_map<int,set<string>> grade_name;
string g[N];
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
for(int i=0;i<n;i++){
string name;
int grade,sex,num;
cin>>name>>grade>>sex>>num;
PII sex_num={sex,num};
mp[name]={grade,sex_num};
grade_name[grade].insert(name);
}
for(auto it=grade_name.begin();it!=grade_name.end();it++){
string s="";
for(auto i=it->second.begin();i!=it->second.end();i++){
s=s+(*i);
s+="
";
}
g[it->first]=s;
}
cin>>m;
while(m--){
int t;
cin>>t;
if(t==1){
string name;
cin>>name;
//PIII gsn = mp[name];
cout<<mp[name].first<<" "<<mp[name].second.second<<" "<<mp[name].second.first<<endl;
}
else{
int grade;
cin>>grade;
cout<<g[grade];
}
}
return 0;
}
G 贪吃的派蒙
大意:
n个人,k份蛋糕。每个人都可以有一个饭量ai,每次轮到一个人的时候,可以取1到ai份蛋糕
但是这n个人里面有一个贪心者派蒙,他是ai最大的那个人,他一定会取走ai份饭
所以现在大家想让他刷盘子,也就是最后一个取完蛋糕,问能否使他最后一个取完全部的蛋糕
注意取完n个人一轮后,如果还有蛋糕,则从第1个人开始取第二轮
思路:
直接每一轮模拟即可,从左到右算最小值和最大值,看能否将派蒙包含进里面即可
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n, k, t;
queue<LL> q;
int main() {
cin >> t;
while (t--) {
cin >> n >> k;
LL p = 0;
while(!q.empty()) q.pop();
for (int i = 0; i < n; i++) {
LL x;
cin >> x;
p = max(p, x);
q.push(x);
}
LL l = 0, r = 0;
while (1) {
LL x = q.front();
q.pop();
if (x == p) {
r += x;
if (k > l && k <= r) {
cout << "YES
";
break;
}
if (k <= l) {
cout << "NO
";
break;
}
l += x;
} else {
l++;
r += x;
}
q.push(x);
}
}
return 0;
}
H 数羊
大意:
给出n和m的值,求A(n,m):
思路:
先暴力打表,然后找出规律即可:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 2e5 + 10;
LL n, m, T;
LL qmi(LL a, LL k, LL p) {
LL res = 1 % p; // res记录答案, 模上p是为了防止k为0,p为1的特殊情况
while(k) { // 只要还有剩下位数
if (k & 1) res = (LL)res * a % p; // 判断最后一位是否为1,如果为1就乘上a,模上p, 乘法时可能爆int,所以变成long long
k >>= 1; // 右移一位
a = (LL) a * a % p; // 当前a等于上一次的a平方,取模,平方时可能爆int,所以变成long long
}
return res;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> T;
while(T--) {
cin >> n >> m;
if (n == 1) cout << 2 << endl;
else if (n == 2) cout << 4 << endl;
else if (!m) cout << (n + 2) % 998244353 << endl;
else if (m == 1) cout << n * 2 % 998244353 << endl;
else cout << 8 * qmi(2, n - 3, 998244353) % 998244353 << endl;
}
return 0;
}
I 买花
大意:
n个花,分k天买(k>1,即不能一天全买完),第一天可以买任意朵花,之后每一天买花的数量为前一天的两倍。
问能否在15天内买够n朵花
思路:
设第一天买的花为x个,那么买2天就是买2x+x个,买3天就是买4x+2x+x个...
所以可以枚举买2到15天的情况,也就是枚举能买到x的倍数,然后看n能否整除某个倍数即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int t, n;
int main() {
cin >> t;
while (t--) {
cin >> n;
int flag = 0;
for (int i = 2; i <= 15; i++) {
if (n % ((1 << i) - 1) == 0) {
flag = 1;
}
}
if (flag) cout << "YE5" << endl;
else
cout << "N0" << endl;
}
return 0;
}
J 这是一题简单的模拟
大意:
从0号点出发到n个城市,然后返回0号点
现在给出所有的路径,以及k个方案
问花费最少的方案的花费是多少
思路:
直接模拟即可...
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 3e2 + 10;
int n, m, k;
int g[MAXN][MAXN];
unordered_map<int, int> mp;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m;
memset(g, -1, sizeof g);
for (int i = 1, a, b, c; i <= m; ++i) {
cin >> a >> b >> c;
g[a][b] = g[b][a] = c;
}
cin >> k;
LL res = 1e18;
while(k--) {
int t;
cin >> t;
int curpos = 0;
LL tmp = 0, flg = 1;
mp.clear();
for (int i = 1, p; i <= t; ++i) {
mp[curpos]++;
// cout << "cur: " << curpos << endl;
cin >> p;
if (g[curpos][p] != -1) {
tmp += g[curpos][p];
curpos = p;
}
else {
flg = 0;
}
}
mp[curpos]++;
if (g[curpos][0]) tmp += g[curpos][0];
else flg = 0;
for (int i = 1; i <= n; ++i) if (mp[i] != 1) {
flg = 0;
// cout << "ev: " << i << endl;
}
if (flg) {
res = min(res, (LL)tmp);
}
}
if (res != 1e18) cout << res << endl;
else cout << -1 << endl;
return 0;
}
K 黑洞密码
大意:
输入一个字符串,然后进行如下操作:
1.确定讯息的长度为32;
2.字符串中第(4n+1sim4n+4)的字母和第(4n+1sim4n+4)的数字为一组,共4组;
3.每组的第1,2,3,4个字符分别往后推每组第1,2,3,4个数字个数 例:如第一个字母为a,第一个数字为3,转换后变为d,'z'之后是'B','Z'之后是'b';
4.将每组内部字母的顺序颠倒;
5.将四组字符合并就是最后的讯息。
思路:
直接模拟,但是需要注意的是,题目中说了z如果往后移动1位那么会变为B,Z移动一位会变为b,比较坑
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
string s;
char ch[50], num[50];
string biao =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int main() {
cin >> s;
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < s.size(); i++) {
if (s[i] >= '0' && s[i] <= '9')
num[++cnt1] = s[i];
else
ch[++cnt2] = s[i];
}
string res = "";
for (int i = 0; i <= 3; i++) {
string temp = "";
for (int j = 1; j <= 4; j++) {
char now;
if(ch[i * 4 + j]>='a'&&ch[i * 4 + j]<='z'){
now = biao[ch[i * 4 + j]-'a' + num[i * 4 + j] - '0'];
if (now >= 'A' && now <= 'Z') now++;
}
else {
now = biao[ch[i * 4 + j]-'A'+26 + num[i * 4 + j] - '0'];
if (now >= 'a' && now <= 'z') now++;
}
temp.push_back(now);
}
//cout << temp << endl;
reverse(temp.begin(),temp.end());
res = res + temp;
}
cout << res << endl;
return 0;
}
L 建立火车站
大意:
给出n个城市,在这些城市之间可以建立k个车站,问最远的两个车站的最小值是多少(城市也需要看做车站)
需要注意车站位置必须是整数。
思路:
首先将每个区间的距离扔到优先队列里,然后每次都将队头的元素多加一个车站,然后再扔到优先队列里即可
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<double, double> PII;
int const N = 2e5 + 10;
int n, k;
double a[N];
priority_queue<PII, vector<PII>, less<PII> > q;
int main() {
cin >> n >> k;
cin >> a[1];
for (int i = 2; i <= n; i++) {
cin >> a[i];
}
sort(a + 1, a + 1 + n);
for (int i = 2; i <= n; i++) {
q.push({a[i] - a[i - 1], 1});
}
while (k--) {
PII t = q.top();
double num = t.second;
double p = t.first * num;
q.pop();
q.push({p / (num + 1), num + 1});
}
cout << ceil(q.top().first) << endl;
//printf("%lld
", ceil(q.top().first));
return 0;
}