藍橋杯第七屆(2016年)省賽軟件類C++A組解題報告
Apare_xzc 2020/3/4
考生須知:
1.網友年齡
分析:
枚舉網友的年齡,從10開始到99,逐個判斷,符合條件的計數即可。
代碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x = 10;
int cnt = 0;
for(int x = 27;x<100;++x)
{
int y = x-27;
int a = y%10,b = y/10;
if(a*10+b==x)
{
++cnt;
cout<<x<<endl;
}
}
cout<<"ans = "<<cnt<<endl;
return 0;
}
答案:7
符合條件的年齡有:30
,41
,52
,63
,74
,85
,96
共七個。
2. 生日蠟燭
分析:
這道題明顯可以口算出來。我們可以選擇最暴力的兩重循環找答案,也可以對236分解質因數,稍加分析,口算出答案。
通過分解質因數,我們知道236 = 2 * 2 * 2 * 59
,我們不妨設這個人開始過生日party的年齡爲x,今年的年齡爲y,則x + (x+1) + (x+2) + ... + (y-1) + y = 236
,我們用等差數列求和公式可得:(x+y) * (y-x+1) = 236
。
我們稍加分析可知:x+y 和 y-x的奇偶性相同,那麼x+y和y-x+1一定是一奇一偶。於是只能是一個59
,一個8
。於是:
x+y = 59
y-x = 7
聯立可得:x = 26
, y = 33
答案:26
分解質因數的代碼:
#include <bits/stdc++.h>
using namespace std;
void f(int x)
{
for(int i=2;i<=x;++i)
{
while(x%i==0) cout<<i<<",",x/=i;
}
cout<<endl;
}
int main()
{
f(236);
//236 = 2*2*2*59
//(st+ed)*(ed-st+1) = 472;
//st = 26 ed = 33
return 0;
}
3. 方格填數
分析:
簡單dfs, 判斷,剪枝。我們可以對這10個塊進行如下的編號:
我們只需要dfs一個長度爲10的序列,序列的每個位置都可以填0
到9
的某個數,然後判斷是否合法即可。
我們可以預處理出每個位置相鄰的位置(上下左右對角)有哪些,存到vector中,便於我們dfs時判斷。只要每個位置和比它編號小的所有位置都不相鄰,那麼這個填法一定合理。
代碼:
#include <bits/stdc++.h>
using namespace std;
long long ans = 0;
int a[] = {0,0,0,0,1,1,1,1,2,2,3,3,3,4,4,4,4,5,5,5,6,7,8};
int b[] = {1,3,4,5,2,4,5,6,5,6,4,7,8,5,7,8,9,6,8,9,9,8,9};
int record[12];
vector<int> v[12];
void dfs(int x)
{
if(x==10)
{
++ans;
// for(int i=0;i<10;++i) printf("%d%c",record[i],i==9?'\n':' ');
return;
}
bool vs[12] = {0};
int len = v[x].size();
for(int i=0;i<len;++i)
{
vs[record[v[x][i]]]= true;
}
for(int i=0;i<10;++i)
{
if(vs[i]) continue;
record[x] = i;
dfs(x+1);
}
}
int main()
{
// freopen("outC.txt","w",stdout);
int L = sizeof(a)/sizeof(a[0]);
for(int i=0;i<L;++i)
{
v[b[i]].push_back(a[i]);
}
ans = 0;
dfs(0);
cout<<ans<<endl;
// 702107280
// fclose(stdout);
return 0;
}
4. 快速排序
#include <stdio.h>
void swap(int a[], int i, int j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
int partition(int a[], int p, int r)
{
int i = p;
int j = r + 1;
int x = a[p];
while(1){
while(i<r && a[++i]<x);
while(a[--j]>x);
if(i>=j) break;
swap(a,i,j);
}
//請填空______________________;
return j;
}
void quicksort(int a[], int p, int r)
{
if(p<r){
int q = partition(a,p,r);
quicksort(a,p,q-1);
quicksort(a,q+1,r);
}
}
int main()
{
int i;
int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
int N = 12;
quicksort(a, 0, N-1);
for(i=0; i<N; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}
//注意:只填寫缺少的內容,不要書寫任何題面已有代碼或說明性文字。
分析:
快速排序可以用遞歸實現(也可以用循環)。對a[p],a[p+1],a[p+2], … ,a[r-1],a[r]這個序列排序,我們隨機找序列中的某個數作爲參考,題目選的是第一個數a[p],然後我們要實現大於x的全部放到x右邊,小於x的全部放到x左邊,最後返回x在數組中的下標。根據樣例手動模擬一下不難得到答案。
答案:swap(a,p,j)
5. 消除尾一
#include <stdio.h>
void f(int x)
{
int i;
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf(" ");
x = _______________________;
for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
printf("\n");
}
int main()
{
f(103);
f(12);
return 0;
}
//注意:只填寫缺少的內容,不要書寫任何題面已有代碼或說明性文字。
分析:
顯然題目要求一行代碼將x末尾連續的1都消去。
我們想到了樹狀數組中lowbit()這個函數。int lowbit(int x){return x&(-x);}
返回的是整數x的二進制從後往前數第一個1以及後面的0的十進制數值(不懂的話百度一下吧)我們一先將x加1,變成xxxxx10000的形式,然後再x -= lowbit(x)
答案:(x+1)-((x+1)&(-x-1))
或者 x&(x+1)
6. 寒假作業
分析:
dfs即可。我們需要一些剪枝,減少不必要的計算。比如,加號兩邊都要小於13,被減數小於減數,乘號兩端相乘不大於13,被除數要能被除數整除…
代碼:
(由於剪枝,代碼稍長,但都可複製粘貼一個case)
#include <bits/stdc++.h>
using namespace std;
int r[15];
long long ans = 0;
bool vis[15];
void dfs(int x)
{
if(x==12)
{
++ans;
for(int i=0;i<12;++i) printf("%d%c",r[i],i==11?'\n':' ');
return;
}
if(x==0)
{
for(int i=1;i<=12;++i)
{
if(vis[i]) continue;
r[x] = i;
vis[i] = true;
dfs(x+1);
vis[i] = false;
}
}
else if(x==1)
{
for(int i=1;i+r[0]<=13;++i)
{
if(vis[i]) continue;
r[x] = i;
vis[i] = true;
dfs(x+1);
vis[i] = false;
}
}
else if(x==2)
{
int y = r[0]+r[1];
if(y<=13&&!vis[y])
{
r[x] = y;
vis[y] = true;
dfs(x+1);
vis[y] = false;
}
}
else if(x==3)
{
for(int i=2;i<=13;++i)
{
if(vis[i]) continue;
r[x] = i;
vis[i] = true;
dfs(x+1);
vis[i] = false;
}
}
else if(x==4)
{
for(int i=1;i<r[3];++i)
{
if(vis[i]) continue;
r[x] = i;
vis[i] = true;
dfs(x+1);
vis[i] = false;
}
}
else if(x==5)
{
int dif = r[3]-r[4];
if(!vis[dif])
{
r[x] = dif;
vis[dif] = true;
dfs(x+1);
vis[dif] = false;
}
}
else if(x==7)
{
for(int i=1;i*r[6]<=13;++i)
{
if(vis[i]) continue;
r[x] = i;
vis[i] = true;
dfs(x+1);
vis[i] = false;
}
}
else if(x==8)
{
int p = r[6]*r[7];
if(p<=13&&!vis[p])
{
r[x] = p;
vis[p] = true;
dfs(x+1);
vis[p] = false;
}
}
else if(x==10)
{
for(int i=1;i<r[9];++i)
{
if(vis[i]||r[9]%i!=0) continue;
r[x] = i;
vis[i] = true;
dfs(x+1);
vis[i] = false;
}
}
else if(x==11)
{
int d = r[9]/r[10];
if(!vis[d])
{
r[x] = d;
vis[d] = true;
dfs(x+1);
vis[d] = false;
}
}
else
{
for(int i=1;i<=13;++i)
{
if(vis[i]) continue;
r[x] = i;
vis[i] = true;
dfs(x+1);
vis[i] = false;
}
}
}
int main()
{
dfs(0);
cout<<"ans = "<<ans<<endl;
return 0;
}
答案爲:64
所有填法如下:
1 8 9 13 6 7 2 5 10 12 3 4
1 8 9 13 6 7 2 5 10 12 4 3
1 8 9 13 6 7 3 4 12 10 2 5
1 8 9 13 6 7 3 4 12 10 5 2
1 8 9 13 6 7 4 3 12 10 2 5
1 8 9 13 6 7 4 3 12 10 5 2
1 8 9 13 6 7 5 2 10 12 3 4
1 8 9 13 6 7 5 2 10 12 4 3
1 8 9 13 7 6 2 5 10 12 3 4
1 8 9 13 7 6 2 5 10 12 4 3
1 8 9 13 7 6 3 4 12 10 2 5
1 8 9 13 7 6 3 4 12 10 5 2
1 8 9 13 7 6 4 3 12 10 2 5
1 8 9 13 7 6 4 3 12 10 5 2
1 8 9 13 7 6 5 2 10 12 3 4
1 8 9 13 7 6 5 2 10 12 4 3
6 7 13 9 1 8 2 5 10 12 3 4
6 7 13 9 1 8 2 5 10 12 4 3
6 7 13 9 1 8 3 4 12 10 2 5
6 7 13 9 1 8 3 4 12 10 5 2
6 7 13 9 1 8 4 3 12 10 2 5
6 7 13 9 1 8 4 3 12 10 5 2
6 7 13 9 1 8 5 2 10 12 3 4
6 7 13 9 1 8 5 2 10 12 4 3
6 7 13 9 8 1 2 5 10 12 3 4
6 7 13 9 8 1 2 5 10 12 4 3
6 7 13 9 8 1 3 4 12 10 2 5
6 7 13 9 8 1 3 4 12 10 5 2
6 7 13 9 8 1 4 3 12 10 2 5
6 7 13 9 8 1 4 3 12 10 5 2
6 7 13 9 8 1 5 2 10 12 3 4
6 7 13 9 8 1 5 2 10 12 4 3
7 6 13 9 1 8 2 5 10 12 3 4
7 6 13 9 1 8 2 5 10 12 4 3
7 6 13 9 1 8 3 4 12 10 2 5
7 6 13 9 1 8 3 4 12 10 5 2
7 6 13 9 1 8 4 3 12 10 2 5
7 6 13 9 1 8 4 3 12 10 5 2
7 6 13 9 1 8 5 2 10 12 3 4
7 6 13 9 1 8 5 2 10 12 4 3
7 6 13 9 8 1 2 5 10 12 3 4
7 6 13 9 8 1 2 5 10 12 4 3
7 6 13 9 8 1 3 4 12 10 2 5
7 6 13 9 8 1 3 4 12 10 5 2
7 6 13 9 8 1 4 3 12 10 2 5
7 6 13 9 8 1 4 3 12 10 5 2
7 6 13 9 8 1 5 2 10 12 3 4
7 6 13 9 8 1 5 2 10 12 4 3
8 1 9 13 6 7 2 5 10 12 3 4
8 1 9 13 6 7 2 5 10 12 4 3
8 1 9 13 6 7 3 4 12 10 2 5
8 1 9 13 6 7 3 4 12 10 5 2
8 1 9 13 6 7 4 3 12 10 2 5
8 1 9 13 6 7 4 3 12 10 5 2
8 1 9 13 6 7 5 2 10 12 3 4
8 1 9 13 6 7 5 2 10 12 4 3
8 1 9 13 7 6 2 5 10 12 3 4
8 1 9 13 7 6 2 5 10 12 4 3
8 1 9 13 7 6 3 4 12 10 2 5
8 1 9 13 7 6 3 4 12 10 5 2
8 1 9 13 7 6 4 3 12 10 2 5
8 1 9 13 7 6 4 3 12 10 5 2
8 1 9 13 7 6 5 2 10 12 3 4
8 1 9 13 7 6 5 2 10 12 4 3
7. 剪郵票
分析:
12個裏面選5個,我們可以dfs枚舉所有選法,然後再判斷每種選法5張郵票是否都連在一起。
爲了做到不重不漏,我們dfs枚舉5個郵票的時候不妨按序號升序枚舉
判連通可以用dfs,從某個塊開始dfs,如果所有塊都能到達,則是合法的。
代碼:
#include <bits/stdc++.h>
using namespace std;
int a[] = {1,1,2,2,3,3,4,5,5,6, 6,7, 7, 8, 9,10,11};
int b[] = {2,5,3,6,4,7,8,6,9,7,10,8,11,12,10,11,12};
int r[5];
bool vis[15];
vector<int> v[15];
int ans;
bool vs[15];
bool see[15];
void DFS(int x)
{
see[x] = true;
int len = v[x].size();
for(int i=0;i<len;++i)
{
int to = v[x][i];
if(!vs[to]) continue;
if(see[to]) continue;
DFS(to);
}
}
void judge()
{
memset(vs,false,sizeof(vs));
memset(see,false,sizeof(see));
for(int i=0;i<5;++i)
vs[r[i]] = true;
DFS(r[0]);
int cnt = 0;
for(int i=1;i<=12;++i)
{
if(see[i]) ++cnt;
}
if(cnt==5)
{
++ans;
for(int i=0;i<5;++i) printf("%2d%c",r[i],i==4?'\n':' ');
}
}
void dfs(int x)
{
if(x==5)
{
judge();
return;
}
int down = x==0?1:r[x-1]+1;
for(int i=down;i<=12;++i)
{
if(vis[i]) continue;
r[x] = i;
vis[i] = true;
dfs(x+1);
vis[i] = false;
}
}
int main()
{
int L = sizeof(a)/sizeof(a[0]);
for(int i=0;i<L;++i)
{
v[a[i]].push_back(b[i]);
v[b[i]].push_back(a[i]);
}
dfs(0);
cout<<"ans = "<<ans<<endl;
return 0;
}
答案爲:116
8. 四平方和
分析:又是dfs…
代碼:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e6+10;
bool is2[maxn];
long long p2[3000];
int r[4];
bool ok;
int X;
void dfs(int x,int preSum)
{
if(ok) return;
if(x==3)
{
int remain = X-preSum;
if(remain>=0&&is2[remain])
{
int y = sqrt(remain);
if(y>=r[2]&&y*y==remain)
{
ok = true;
for(int i=0;i<3;++i)
cout<<r[i]<<" ";
cout<<y<<endl;
}
}
return;
}
if(x==0)
{
for(int i=0;p2[i]*4<=X;++i)
{
r[0] = i;
dfs(1,i*i);
}
}
else
{
for(int i=r[x-1];p2[i]*(4-x)+preSum<=X;++i)
{
r[x] = i;
dfs(x+1,preSum+p2[i]);
}
}
}
int main()
{
for(int i=0;i*i<maxn;++i)
{
is2[i*i] = true;
}
for(int i=0;i<3000;++i)
{
p2[i] = i*i;
}
while(cin>>X)
{
ok = false;
dfs(0,0);
}
return 0;
}
9. 密碼脫落
樣例輸入1
ABCBA
樣例輸出1
0
樣例輸入2
ABDCDCBABC
樣例輸出2
3
分析:
意思就是給一個字符串,問你最少添加幾個字符就可以變成迴文串。
我們想到了編輯距離。 編輯距離是說把某個字符串增,刪,改一個字符,若干次,最少幾次能變成另一個字符串。編輯距離就可以用dp做。
迴文串有一個性質:如果a是迴文串,那麼a刪掉左右兩端的字符,仍是迴文串(長度>=2)。同理,迴文子串左右兩邊加上相同的字符仍是迴文串。
如果知道了子串a[L~R]變成迴文串的最少操作數,那麼a[L-1,R+1]也可以推出
令dp[L][R]爲子串 str[L] 到 str[R] 變爲迴文串需要的最少操作數
則轉移方程如下:
dp[L][L] = 0
dp[L][L+1] = (str[L]==str[L+1])?0:1
dp[L][R] = min(dp[L+1][R-1]+(str[L]!=str[R]),min(dp[L][R-1],dp[L+1][R])+1)
我們發現,dp時要用到長度較短的子串的信息,我們應該按字符串長度從小到大dp。所以這個題用區間DP即可。
代碼:
#include<bits/stdc++.h>
using namespace std;
char s[1005];
int dp[1003][1003];
int main()
{
while(scanf("%s",s)!=EOF)
{
int len = strlen(s);
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<len;++i) dp[i][i]=0;
for(int i=0;i+1<len;++i)
{
dp[i][i+1] = (s[i]==s[i+1])?0:1;
}
for(int L=3;L<=len;++L)
{
for(int l=0;l+L-1<len;++l)
{
int r = l+L-1;
dp[l][r] = min(dp[l+1][r],dp[l][r-1])+1;
dp[l][r] = min(dp[l][r],dp[l+1][r-1]+(s[l]==s[r]?0:1));
}
}
cout<<dp[0][len-1]<<endl;
}
return 0;
}
10. 最大比例
分析:
要得到最大比例,我們要先求出現有的比例。我們先對所有分數從小到大排序。然後每個數和前一個相除,得到n-1個比例。
我們將這n-1個比例排序,我們要求的答案ans
一定是這些比例的約數,並且滿足ans ^ t == 比例Ki
。我們假設某個比例x可以表示爲分數 up/down
up和down互質且down不爲零
x = up / down
,
up = P1^C1 * P2^C2 * ... * Pm^Cm
,
down = Q1^D1 * Q2^D2 * ... * Qn^Dn
,
(其中,Pi, Qi 都是質數)
設我們求的答案ans可以表示爲U/D
我們將U和D分解得到如下的表示:
U = P1^c1 * P2^c2 * ... * Pm^cm
D = Q1^d1 * Q2^d2 * ... * Qn^dn
我們現在要求的是:最大的U/D, 使得對於每個比例K, 都存在正整數ti, 使得U^ti = K.up D^ti = K.down
即存在{t1,t2,t3… tn-1}使得對於每個得到的比例Ki,滿足:
c1*ti = Ki.C1; c2*ti = Ki.C2; ... cm*ti = Ki.Cm
d1*ti = Ki.D1; d2*ti = ki.D2; ... dn*ti = Ki.Dn
我們只需要對每個質因數Pi,求再每個比例中對應的係數的最大公約數即可。
代碼:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
bool notPrime[maxn];
int sushu[maxn/10],cntPrime;
struct Node{
long long up,down;
Node(){up=0;down=1;}
Node(long long u,long long d)
{
up = u; down = d;
}
bool operator < (const Node& rhs)const
{
return up*rhs.down < rhs.up*down;
}
}node[200];
map<long long,int> mpu[100],mpd[100];
long long a[maxn];
long long gcd(long long x,long long y)
{
if(y==0) return x;
return gcd(y,x%y);
}
long long fast_pow(long long a,long long b)
{
if(a==0) return 0;
long long ans = 1;
while(b)
{
if(b&1) ans = ans*a;
a = a*a;
b>>=1;
}
return ans;
}
void solve(long long small,long long big,int i)
{
long long g = gcd(big,small);
small /= g;
big /= g;
node[i] = Node(big,small);
}
void getPrime();
void fenjie(long long x,map<long long,int>& mp)
{
mp.clear();
for(int i=0;i<cntPrime&&sushu[i]<=x/sushu[i];++i)
{
int p = sushu[i];
if(x%p) continue;
int c = 0;
while(x%p==0)
++c, x/=p;
mp[p] = c;
}
if(x>1) mp[x] = 1;
}
int main()
{
getPrime();
set<long long> Set;
int n;
long long x;
cin>>n;
for(int i=1;i<=n;++i)
{
scanf("%lld",&x);
Set.insert(x);
}
set<long long>::iterator it;
int cnt = 0;
for(it=Set.begin();it!=Set.end();++it)
{
a[++cnt] = *it;
}
for(int i=1;i<=cnt;++i)
for(int i=1;i<cnt;++i)
{
solve(a[i],a[i+1],i-1);
}
--cnt;
sort(node,node+cnt);
bool has1 = false;
for(int i=0;i<cnt;++i)
{
fenjie(node[i].up,mpu[i]);
if(node[i].down!=1)
fenjie(node[i].down,mpd[i]);
else
has1 = true;
}
long long ansu = 1,ansd = 1;
map<long long,int> mp;
vector<long long> v;
for(map<long long,int>::iterator it=mpu[0].begin();it!=mpu[0].end();++it)
{
v.push_back(it->first);
}
int len = v.size();
for(int i=0;i<len;++i)
{
long long p = v[i];
int g = mpu[0][p];
for(int j=1;j<cnt;++j)
{
g = gcd(g,mpu[j][p]);
if(g==1) break;
}
mp[p] = g;
}
ansu = 1;
for(map<long long,int>::iterator it=mp.begin();it!=mp.end();++it)
{
ansu *= fast_pow(it->first,it->second);
}
if(has1) ansd = 1;
else
{
mp.clear();
v.clear();
for(map<long long,int>::iterator it=mpd[0].begin();it!=mpd[0].end();++it)
{
v.push_back(it->first);
}
int len = v.size();
for(int i=0;i<len;++i)
{
long long p = v[i];
int g = mpd[0][p];
for(int j=1;j<cnt;++j)
{
g = gcd(g,mpd[j][p]);
if(g==1) break;
}
mp[p] = g;
}
ansd = 1;
for(map<long long,int>::iterator it=mp.begin();it!=mp.end();++it)
{
ansd *= fast_pow(it->first,it->second);
}
}
cout<<ansu<<"/"<<ansd<<endl;
return 0;
}
void getPrime()
{
int cnt = 0;
int n = 1e6+2;
for(int i=2;i<=n;++i)
{
if(!notPrime[i]) sushu[cnt++] = i;
for(int j=0;j<cnt&&1ll*i*sushu[j]<=n;++j)
{
notPrime[i*sushu[j]] = true;
if(i%sushu[j]==0) break;
}
}
cntPrime = cnt;
}
xzc
2020.3.4 17:36