(k^{h+1}-1)/(k-1)(kh+1−1)/(k−1)
k^{h-1}kh−1
k^hkh
(k^{h-1})/(k-1)(kh−1)/(k−1)
二、問題求解(每題5分,共10分)
1. 甲乙丙丁四人在考慮周末要不要外出郊游。
已知①如果周末下雨,並且乙不去,則甲一定不去;②如果乙去,則丁一定去;③如果丙去,則丁一定不去;④如果丁不去,而且甲不去,則丙一定不去。如果周末丙去了,則甲_____(去了/沒去)(1分),乙_____(去了/沒去)(1分),丁_____(去了/沒去)(1分),周末_____(下雨/沒下雨)(2分)。
答案:去了,沒去,沒去,沒下雨
解析:送分題,根據條件判斷即可
2. 方程 a*b =(a or b) * (a andb),在a, b都取[0、31]中的整數時,共有______組解。(*表示乘法;or表示按位或運算;and表示按位與運算)
解析:使得a|b==max(a,b),a&b==min(a,b)
顯然,a,b存在子集關系時上面的式子才能成立。
例如:1011|1001=1011=max(1011,1001)
可以自己舉例驗證QwQ
我們設b是a的子集,枚舉a在二進制下有多少個1,即從5里面取i個1,i從0到5。每個i都是一個C(5, i)
接着枚舉子集,有2^i中方案(每一個1都看看放還是不放)
C(5,0)*2^0 +C(5,1)*2^1+…+C(5,5)*2^5
= 1*1 + 5*2 + 10*4 + 10*8 + 5*16 + 1*32
= 243
最后,由於我們限制了a>b,所以答案要*2
但是a==b的情況會被多算,所以答案減去32
最后結果:2*243 – 32 = 452
四、閱讀程序寫結果(共 4 題,每題8 分,共計 32 分)
1.
#include
int main() {
int x;
scanf("%d", &x);
int res = 0;
for (int i = 0; i < x; ++i) {
if (i * i % x == 1) {
++res;
}
}
printf("%d", res);
return 0;
}
輸入:15
輸出:4
解析:簡單模擬
2.
#include
int n, d[100];
bool v[100];
int main() {
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", d + i);
v[i] = false;
}
int cnt = 0;
for (int i = 0; i < n; ++i) {
if (!v[i]) {
for (int j = i; !v[j]; j = d[j]) {
v[j] = true;
}
++cnt;
}
}
printf("%d\n", cnt);
return 0;
}
輸入:10 7 1 4 3 2 5 9 8 0 6
輸出:6
解析:繼續模擬(逃
3.
#include
using namespace std;
string s;
long longmagic(int l, int r) {
long long ans = 0;
for (int i = l; i <= r; ++i) {
ans = ans * 4 + s[i] - 'a' + 1;
}
return ans;
}
int main() {
cin >> s;
int len = s.length();
int ans = 0;
for (int l1 = 0; l1 < len; ++l1) {
for (int r1 = l1; r1 < len; ++r1) {
bool bo = true;
for (int l2 = 0; l2 < len; ++l2) {
for (int r2 = l2; r2 < len; ++r2) {
if (magic(l1, r1) == magic(l2, r2)&& (l1 != l2 || r1 != r2)) {
bo = false;
}
}
}
if (bo) {
ans += 1;
}
}
}
cout << ans << endl;
return 0;
}
輸入:abacaba
輸出:16
解析:magic(l,r)是l-r的hash,枚舉兩個子串,答案就是不重復出現的子串個數,手動枚舉。
4.
#include
using namespace std;
const int N =110;
bool isUse[N];
int n, t;
int a[N], b[N];
bool isSmall() {
for (int i = 1; i <= n; ++i)
if (a[i] != b[i]) return a[i] < b[i];
return false;
}
boolgetPermutation(int pos) {
if (pos > n) {
return isSmall();
}
for (int i = 1; i <= n; ++i) {
if (!isUse[i]) {
b[pos] = i; isUse[i] = true;
if (getPermutation(pos + 1)) {
return true;
}
isUse[i] = false;
}
}
return false;
}
void getNext() {
for (int i = 1; i <= n; ++i) {
isUse[i] = false;
}
getPermutation(1);
for (int i = 1; i <= n; ++i) {
a[i] = b[i];
}
}
int main() {
scanf("%d%d", &n, &t);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= t; ++i) {
getNext();
}
for (int i = 1; i <= n; ++i) {
printf("%d", a[i]);
if (i == n) putchar('\n'); else putchar('');
}
return 0;
}
輸入1:6 10 1 6 4 5 32
輸出 1:2 1 3 5 6 4 (3 分)
輸入2:6 200 1 5 3 4 26
輸出 2:3 2 5 6 1 4 (5 分)
解析:這一大堆函數就是求這個排列的下一個……手算即可(當然如果你覺得200算不出來可以使用康托展開)
五、完善程序(共 2 題,每題 14 分,共計 28 分)
1. 對於一個1到n的排列p(即1到n中每一個數在p中出現了恰好一次),令qi為第i個位置之后第一個比pi值更大的位置,如果不存在這樣的位置,則qi =n+1。
舉例來說,如果n=5且p為1 5 4 2 3,則q為2 6 6 5 6。
下列程序讀入了排列p,使用雙向鏈表求解了答案。試補全程序。(第二空2分,其余3分)
數據范圍 1 ≤ n ≤ 105。
#include
using namespace std;
const int N =100010;
int n;
int L[N], R[N],a[N];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) {
int x;
cin >> x;
a[x] = i ;
}
for (int i = 1; i <= n; ++i) {
R[i]= i + 1;
L[i] = i - 1;
}
for (int i = 1; i <= n; ++i) {
L[ R[a[i]]] = L[a[i]];
R[L[a[i]]] = R[a[i] ];
}
for (int i = 1; i <= n; ++i) {
cout << R[i]<< " ";
}
cout << endl;
return 0;
}
解析:
純靠猜。1空發現沒有直接讀入,肯定有鬼……瞎猜一種方法就行
2空仿寫下句……
3,4空互相仿寫……
5空我們肯定要求這個數右邊比他大的數的位置,所以輸出R
當然我蒻看不懂,有心情研究的julao們可以再去找找……
2. 一只小豬要買 N 件物品(N 不超過 1000)。
它要買的所有物品在兩家商店里都有賣。第 i 件物品在第一家商店的價格是 a[i],在第二家商店的價格是 b[i],兩個價格都不小於 0 且不超過 10000。如果在第一家商店買的物品的總額不少於 50000,那么在第一家店買的物品都可以打 95 折(價格變為原來的 0.95 倍)。
求小豬買齊所有物品所需最少的總額。
輸入:第一行一個數 N。接下來 N 行,每行兩個數。第 i 行的兩個數分別代表 a[i],b[i]。
輸出:輸出一行一個數,表示最少需要的總額,保留兩位小數。
試補全程序。(第一空 2 分,其余 3 分)
#include <cstdio> #include <algorithm> using namespace std; const int Inf = 1000000000; const int threshold = 50000; const int maxn = 1000; int n, a[maxn], b[maxn]; bool put_a[maxn]; int total_a,total_b; double ans; intf[threshold]; int main() { //第一部分 scanf("%d",&n); total_a= total_b = 0; for(int i = 0; i < n; ++i) { scanf("%d%d",a + i, b + i); if(a[i] <= b[i]) total_a += a[i]; elsetotal_b += b[i]; } ans =total_a + total_b; total_a= total_b = 0; for(int i = 0; i < n; ++i) { if( (1) ) { put_a[i]= true; total_a+= a[i]; }else { put_a[i]= false; total_b+= b[i]; } } if ((2) ) { printf("%.2f",total_a * 0.95 + total_b); return0; } //第二部分 f[0]= 0; for(int i = 1; i < threshold; ++i) f[i]= Inf; inttotal_b_prefix = 0; for(int i = 0; i < n; ++i) if (!put_a[i]) { total_b_prefix += b[i]; for (int j = threshold - 1; j >= 0; --j) { if ( (3) >= threshold && f[j] != Inf) ans = min(ans, (total_a + j +a[i]) * 0.95+ (4) ); f[j] = min(f[j] + b[i], j >= a[i] ? (5) :Inf); } } printf("%.2f",ans); return0; }
解析:
代碼分為兩個部分。
第一部分是一個貪心,我們假設滿足了優惠條件,按照折后價格進行貪心,如果結果滿足了優惠條件就直接輸出,此時如果放棄某些b商品來買a不會再有更優策略
第二部分是一個dp……策略就是把原先買了b的東西買a以獲得折扣
f[i,j]表示前i個物品,在額外在A店花了j元的情況下,購買B店物品花費的最小值。i呢?想想你的01背包是怎么優化的。
3空是一個轉移判斷條件,tot_a+j+a[i]是在a店話費的總錢數(本來花的錢+前面改了的錢+當前物品價格)
4空表示在b商店買的物品總價, total_b + f[j] - total_b_prefix
5空更新,看看這個商品在a商店買還是b商店買
太毒瘤了QwQ