牛客寒假算法基礎集訓營2 解題報告


假算法基礎集訓營名副其實。

只會5題的我真是菜爆了qwq。

所以寫完5題還剩下1h就來寫題解是不是沒救了啊

這場的題解按難度排序...(其實就是我過題的順序)

順序是DJGHC。

賽后吐槽:

A到底卡什么啊
B這么毒瘤的大模擬咋寫啊
我居然還有前50,手速果然重要
想中牛可樂qwq

D

做法:模擬

按題意模擬...

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 100010
int n;
int a[N];
ll ans = 0;
 
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {scanf("%d", &a[i]); if(a[i] < 60) ans += 400;}
    printf("%lld\n", ans);
}

J

做法:貪心

因為可以把復習時間拆開,所以直接按開始考試的時間排序一波。
然后假裝我們可以篡改考試時間,復習完了就讓他考試(也就是+2h)
每次考試前看復習時間有沒有超過考試的開始時間就好了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
#define N 100010
int n;
struct Node {
    ll a, b;
}a[N];
 
bool cmp(Node a, Node b) {
    return a.b < b.b;
}
 
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%lld", &a[i].a);
    for(int i = 1; i <= n; ++i) scanf("%lld", &a[i].b);
    sort(a + 1, a + n + 1, cmp);
    ll cnt = 0;
    for(int i = 1; i <= n; ++i) {
        cnt += a[i].a;
        if(cnt > a[i].b) return puts("NO"), 0;
        cnt += 2;
   //     printf("%lld\n", cnt);
    }
    puts("YES");
    return 0;
}

G

做法:dp

不知道這題的std是啥...賽后看看。
其實這題有原題的...原題:LGOJP2758
其實就是按原題那個做法搞一波,然后看看dp出來的結果會不會小於等於2即可

\(f[i][j]\)表示前\(i\)個字符變成結果串的前\(j\)個字符要變換多少次。
那么刪除即為\(f[i][j]=min(f[i-1][j]+1)\)
插入即為\(f[i][j]=min(f[i][j-1]+1)\)
替換即為\(f[i][j]=min(f[i-1][j-1]+1)\)
初始化邊界為\(f[0][i]=f[i][0]=i\)

#include <bits/stdc++.h>
using namespace std;

#define N 2010
int f[N][N];
char s[N], t[N];
//第一個串到i,第二個串到j最小操作次數 

int main() {
	scanf("%s%s", s + 1, t + 1);
	int n = strlen(s + 1), m = strlen(t + 1);
	for(int i = 1; i <= n; ++i) f[i][0] = i;
	for(int i = 1; i <= m; ++i) f[0][i] = i;
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; j <= m; ++j) {
			if(s[i] == t[j]) {f[i][j] = f[i - 1][j - 1]; continue;} //正好相等就不管 
			f[i][j] = min(min(f[i - 1][j], f[i][j - 1]), f[i - 1][j - 1]) + 1; 
			//刪除,插入,替換 
		}
	}
	if(f[n][m] <= 2) puts("YES");
	else puts("NO");
}

至於這題的LCS做法錯在哪里?
事實上就是因為LCS沒辦法考慮位置。
這里給一組hack數據:
abxyabcd
ababxycd
實際上是no但是LCS做法會輸出yes

H

做法:數論

考慮怎么讓一個數有超過10個因數,顯然只要有4個質因子就夠了。
然后任意兩個數都互質這意味着所有數沒有相同的質因子。
而題目給的因數是\(x*y\)的,這意味着每個數只要有兩個質因子就夠了。
於是我們預處理出前4000個素數,每兩個丟在一起,讓他們組成一個數。
注意要盡量平均不然會超過題目的要求。如:第1個和第4000個組合在一起。
那么這題就做完了。
我忘記把freopen刪掉居然被罰時了QAQ
(代碼里到6000跳是沒有必要的不過懶得改了)

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e8 + 10;
bool vis[N];
ll p[8000], ans[3000];
int n; 

int main() {
//	freopen("ans.out", "w", stdout);
	int cnt = 0;
	for(ll i = 2; i <= (ll)1e8; ++i) {
		if(cnt > 6000) break;
		if(!vis[i]) p[++cnt] = i;
		for(int j = 1; j <= cnt && i * p[j] <= (ll)1e8; ++j) {
			vis[i * p[j]] = 1;
			if(i % p[j] == 0) break;
		}
	}
	for(int i = 1; i <= 2000; ++i) ans[i] = 1;
	for(int i = 1; i <= 2000; ++i) {
		ans[i] *= p[i];
	}
	int qwq = 2000;
	for(int i = 2000; i; --i) {
		ans[i] *= p[++qwq];
	}
	for(int i = 1; i <= 2000; ++i) printf("%lld ", ans[i]);
}

C

做法:數論(找規律)

其實這個是我棄賽了之后水QQ被一個大佬點醒了這題的思路,並且研究了一波樣例解釋才會的。
我寫這種腦洞題是真的菜。

1=1
2=2
3=1+2
4=6-2
5=6-1
6=6
7=6+1
8=6+2
9=6+2+1
10=11-1
11=11
12=11+1
13=11+2
14=11+2+1
15=11+6-2
16=11+6-1
17=11+6
18=11+6+1
19=11+6+2
20=11+6+2+1

並且采用人腦+草稿紙將它繼續推下去
研究一下這個可能會發現一些奇奇怪怪的規律
\(3^0,3^1,3^2...\)這個數列的前綴和中的數會影響答案
(即\(1,4,13,40...\)
即1的答案是1,2-3的答案是2,4-12的答案是3,13-39的答案是4
沒人提醒完全想不到這個結論(我好菜啊)
數論還是要加強qwq
證明我是不會證的,這個結論就是猜出來的...證明之后放std的證明吧

官方題解證明:

什么?你說\(n<=10^{1000}\)
人生苦短我用python

a = 0
b = 0
c = 1
n = int(input())
while b < n :
    a = a + 1
    b = b + c
    c = c * 3
print(a)

其他題真的寫不動了,只能靠手速混在第一頁混日子過。

官方題解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM