Mangata

部分题解

 

前言

    下午在群里面看到一个同学疯狂宣传这个比赛,处于好奇的态度(他说难度有cf1800)我参赛了,可能真的有cf1800的题目,只是我没做出来,离比赛还有十多分钟的时候到了吉首的OJ,注册了账号,稍稍等待之后进入了比赛,出于习惯开了A题,然后想了几分钟没有思路,然后切出去看榜单,看见有人过了J题,我赶紧开了J题,嗯,是个签到题,但是WA了一发,读题的时候漏掉了一个信息,改了后A了,然后开了C,立方和公式稍微一化简就能找到a和b和n的关系,然后一发A了,接着开了E,一发A,刷了下榜单,看到L过了十多人,第一发处理边界的时候出了问题,后面想了下可以直接O(N)扫过去找到最小的,第三发A了,然后此时我在20名左右(暂时靠前),于是又回去看A,稍微想了一下然后又写了个公式,然后自己测试都没过,于是我开始直接硬推公式,想了二十多分钟还是没想出来,于是我开始打表找找规律,在反复观察后,我发现了一个规律,但是当时睡意来了,看着面前的屏幕还有外面刺眼的光线,我的眼睛开始疼痛,强忍着,继续记录规律,在二十多分钟后我把规律转化为了公式,然后交上去第一发CE(本地是能跑的),我把头文件换成了万能头,交上去一发A了,从这一发A之后后面就做的太难受了,接着我开了D,很明显D是一个模拟题,但是一直写不对(写代码细节没写好),然后转身开了F,感觉是一个博弈论,第一发我直接交了cxy上去,然后过了一半的测试点,接着交了几法rand,没过就没看了,然后这个时候我发现K题有几十人切出来了,于是赶忙去切K,由于我的粗心,计算的时候写反了,贡献了5发罚时,此时已经是四点五十二了,最后转身去开D,在贡献了20发罚时的情况下,在最后的5分钟把D题A了,当时激动的喊了出来(^^)。

A: 学习快速幂

传送门
解题思路:通过打标找规律我们能发现,复杂度从\(2^{i}-1\)开始到\(2^{i}-1+2^{i-1}\)是连续的,然后通过两次求和可以算出公式

\[2^{n-1}\times(2^n-1)+\frac{(2^{n-1}-1)\times2^{n-1}}{2}+len\times(2^k-1)+\frac{len\times(len-1)}{2} (k = log(n),len = max(0,n-2^{k-1}-1)) \]

退出公式后我们就可以直接写代码啦^^
Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007;
int cnt = 0;

ll qpow(ll a, ll b) {
	if(b == 0) {
		return 1%mod;
	}
	cnt++;
	if(b%2 == 1) {
		return (a*qpow(a,b-1))%mod;
	}
	else {
		return (qpow(a,b/2)*qpow(a,b/2))%mod;
	}
}
long long f(int n) {
	long long ans = 0;
	while(n) {
		n/=2;
		ans++;
	}
	return ans;
}
ll cal(ll n) {
	ll ans = (ll)pow(2,n-1) * (ll) (pow(2,n)-1) + ((ll)pow(2,n-1)-1)*((ll)pow(2,n-1))/2;
	return ans;
}
ll cal2(ll k, ll len) {
	ll ans =len * (ll)(pow(2,k)-1) + (len-1LL)*len/2;
	return ans;
}
int main()
{
	int t;
//	for(int i = 0;i < 5; ++i) {
//		cnt = 0;
//		qpow(1,i);
//		printf("%d\n",cnt);
//	}

	scanf("%d",&t);
	int n;
	while(t--) {
		scanf("%d",&n);
		if(n == 0) {
			puts("0");
			continue;
		}
		long long k = f(n);
		ll ans = 0;
		for(ll i = 1;i <= k - 1; ++i) {
			ans += cal(i);
		}
		ll len = max(0LL,n - (ll)(pow(2,k-1)-1));
		ans += cal2(k,len);
		printf("%lld\n",ans);
	}


	return 0;
}

C: LeeLdler的数字

传送门
解题思路:把立方和化简一下,我们就能得到a+b=n这个结论,所以随便交一个正整数数据满足之和尾n就行
Code:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	scanf("%d",&n);
	printf("%d %d\n",n-1,1);
	return 0;
}

D: 珍爱生命,远离赌博

传送门
解题思路:我们可以开一个map作为标记,标记这张牌在之前的位置是否出现,然后开一个栈存放牌,输入一个字符串,我们遍历这个字符串,如果发现即将要放进去的这张牌在之前出现过,那么一定在栈中有相同的元素,我们直接对栈开始pop操作直到找到这个元素为止,在pop的过程中别忘了把这些元素的vis清除,如果将要放进去的字符串没有出现过那么久入栈,并且标记该元素已经出现过。注意的是,这题好像卡了常数,我的做法在复杂度上是\(O(N)\)的。
Code:

#define fastcall __attribute__((optimize("-O3")))
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")//这是优化常数的代码
#include<bits/stdc++.h>
using namespace std;

unordered_map<char,bool> vis;
unordered_map<char,int> mp;

char ch[2000006];
stack<char> S;
int main()
{
//	string str;
//	cin>>str;
	scanf("%s",ch);
	mp[\'A\'] = 1;mp[\'2\'] = 2;mp[\'3\'] = 3;mp[\'4\'] = 4;mp[\'5\'] = 5;mp[\'6\'] = 6;mp[\'7\'] = 7;mp[\'8\'] = 8;mp[\'9\'] = 9;mp[\'J\'] = 10;mp[\'Q\'] = 11;mp[\'K\'] = 12;
	int l = 0, r = 0;
	for(int i = 0,len = strlen(ch);i < len; ++i) {
		if(vis[ch[i]]) {//S.size() &&
			if(i & 1) {
				while(S.size() && S.top() != ch[i]) {
					vis[S.top()] = false;
					r += mp[S.top()];
					S.pop();
				}
			//	r += 2 * mp[ch[i]];
				if(S.size()) {
					r += 2*mp[S.top()];
					S.pop();
				}
			}
			else {
				while(S.size() && S.top() != ch[i]) {
					vis[S.top()] = false;
					l += mp[S.top()];
					S.pop();
				}
				//l += 2 * mp[ch[i]];
				if(S.size()) {
					l += 2 * mp[S.top()];
					S.pop();
				}
			}
			vis[ch[i]] = false;
			continue;
		}
		S.push(ch[i]);
		vis[ch[i]] = true;
	}
	if(l == r) {
		puts("-1");
	}
	else {
		if(l < r) {
			printf("lbg %d\n",r);
		}
		else
			printf("zqc %d\n",l);
	}
}

E: 会长的榜单

传送门
解题思路:这题就是把秒数转化为小时、分钟、秒数进行表示,如果该秒数为0则直接输出0
Code:

#include<bits/stdc++.h>
using namespace std;
const int N = 20;
int a[N];
int h[N];
int m[N];
int s[N];
int main()
{
	char name[30];
	int n;
	cin>>n;
	cin>>name;
	for(int i = 0;i < n; ++i) {
		cin>>a[i];
		h[i] = a[i] / 3600;
		a[i] -= h[i] * 3600;
		m[i] = a[i] / 60;
		a[i] -= m[i] * 60;
		s[i] = a[i];
	}
	printf("%s ",name);
	for(int i = 0;i < n; ++i) {
		if(h[i] == 0 && m[i] == 0 && s[i] == 0)
			printf("0%c",i ==n-1?\'\n\':\' \');
		else
			printf("%02d:%02d:%02d%c",h[i],m[i],s[i],i ==n-1?\'\n\':\' \');//格式化输出
	}

}

J: 会长数

传送门
解题思路:暴力把数的每一位拿出来判断,并且把这些数的和判断是否是素数,其实满足条件的数只有23
Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
bool is_prime(int n) {
    if(n==0 || n== 1)
    return false;
    for(int i = 2;i *i <= n; ++i) {
        if(n%i==0)
        return false;
    }
    return true;
}
bool work(int i) {
    int ans = 0;
    while(i) {
        if(!is_prime(i%10))
            return false;
        ans += i%10;
        i/=10;
    }
    if(is_prime(ans))
        return true;
    return false;
}
int main()
{
	vector<int> V;
    for(int i = 10;i <= 100;++i) {
        if(is_prime(i) && work(i)) {
            V.push_back(i);
        }
    }
    printf("%d\n",V.size());
    for(int i = 0, len = V.size();i < len; ++i) {
        printf("%d%c",V[i],i == len-1?\'\n\':\' \');
    }

    return 0;
}

K: 抽奖

传送门
解题思路:我们先统计商品的总数目,然后每次抽取会让商品的总数目减一,每次找到数目剩下的最多的商品,然后计算概率和当前抽取的商品的概率做差计算差值是否大于1/5,如果大于则表示不满足抽奖池的抽奖规律,做一个标记,最后判断标记是否更改,如果被更改的话,就输出BUG,否则输出PASS,时间复杂度\(O(N^2)\)
Code:

#include<bits/stdc++.h>
using namespace std;
const int N = 1005;
int a[N];
int n;
double work() {
	int max_ = a[1];
	for(int i = 2;i <= n; ++i) {
		max_ = max(a[i],max_);
	}
	return (double)max_;
}

int main()
{
	int m,b;
	scanf("%d",&n);
	int tol = 0;
	int max_key;
	for(int i = 1 ;i <= n; ++i)  scanf("%d",&a[i]),tol+=a[i];
	scanf("%d",&m);
	bool fg = true;
	for(int i = 0;i < m; ++i) {
		scanf("%d",&b);
		if(!a[b]) {
			fg = false;
			continue;
		}
		double k = (double)work();
		double k1 = 1.0*k/tol;
		double k2 = 1.0*a[b]/tol;
		if(abs(k1 - k2) > 0.2) {
			fg = false;
		}
		tol --;
		a[b] --;
	}
	if(fg)
		puts("PASS");
	else
		puts("BUG");
	return 0;
}

L: 馋嘴会长逛小吃街

传送门
解题思路:我们先对小吃摊的位置排序,然后从左往右每次去k个连续的小吃摊,然后扫过去找到最小的路程就OK了,时间复杂度\(O(N)\);
Code:

#include<bits/stdc++.h>
using namespace std;
int a[30];
int main()
{
	int t;
	int n,k;
	scanf("%d",&t);
	while(t--) {
		scanf("%d%d",&n,&k);
		for(int i = 1;i <= n; ++i) {
			scanf("%d",&a[i]);
		}
		sort(a+1,a+n+1);
		int ans = 0x3f3f3f3f;
		for(int i = 1;i <= n - k + 1; ++i) {
			ans = min(a[i + k - 1] - a[i], ans);
		}
		printf("%d\n",ans*2);
	}
	return 0;
}

总结

    这次比赛前期状态还是可以,到了中后期思维、写代码速度还有写代码的仔细程度都有明显的下降,特别是D题,思路蛮简单,就是不仔细,写的代码的细节还是没处理好,J题(签到题)也WA了一发,得多加训练了。还有概率论和博弈论这俩东西得找个时间补补,感觉最近得比赛都在考这个,几乎每考必死。其他的题目,有时间我看看能不能补补==

分类:

技术点:

相关文章:

  • 2021-12-06
  • 2022-12-23
  • 2021-11-25
  • 2021-10-09
  • 2021-10-09
猜你喜欢
  • 2021-12-06
  • 2021-12-12
  • 2021-09-18
  • 2021-09-18
  • 2021-09-18
  • 2022-12-23
相关资源
相似解决方案