2015年藍橋杯六屆省賽大學B組真題
1.獎券數目
2.星系炸彈
3.三羊獻瑞
列舉
4.格子中輸出
考點:
printf("%*s%s%*s",(width-strlen(buf)-2)/2," ",buf,(width-strlen(buf)-2)/2); //填空答案
"%*s",數字,字串
表示從第幾個位置開始輸出字串,第一個位置為1號位!
5.九陣列分數
6.移動距離
#include <bits/stdc++.h>
using namespace std;
int main()
{
int w,m,n;
cin>>w>>m>>n;
int h=0;
int z=0;
int x1,y1;
int x2,y2;
int sign=1;
for(int i=1;i<=10000;i++){
//考察走樓梯,語法
z=z+sign;
if(z>w){
z=w;
h++;
sign=-1;
}
if(z<1){
z=1;
sign=1;
h++;
}
if(i==m){
x1=h;
y1=z;
}
if(i==n){
x2=h;
y2=z;
}
}
//注意相減可能<0會抵消,所以abs絕對值
cout<<abs(x2-x1)+abs(y2-y1);
// 請在此輸入您的程式碼
return 0;
}
7.加法變乘法
計算思路:可以求出滿足條件的乘號位置,方法是遍歷這兩個乘號可能的位置
8.牌型種數
思路:暴力,將13種牌型都列舉
#include<bits/stdc++.h>
using namespace std;
int main(){
long long int cnt=0;
for(int a=0;a<=4;a++){
for(int b=0;b<=4;b++){
for(int c=0;c<=4;c++){
for(int d=0;d<=4;d++){
for(int e=0;e<=4;e++){
for(int f=0;f<=4;f++){
for(int g=0;g<=4;g++){
for(int h=0;h<=4;h++){
for(int i=0;i<=4;i++){
for(int j=0;j<=4;j++){
for(int k=0;k<=4;k++){
for(int l=0;l<=4;l++){
for(int m=0;m<=4;m++){
if(a+b+c+d+e+f+g+h+i+j+k+l+m==13){
cnt++;
}
}
}
}
}
}
}
}
}
}
}
}
}
}
cout<<cnt;
}
提交答案:
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<3598180;
return 0;
}
9.生命之樹
演算法:樹狀dp+dfs+鄰接表存圖
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int N=1e5+6;
const int M=2*N;
int e[N];//存放每個點的值
int idx;//當前已經存在幾個點
int h[N] ;//存放頭結點
int ne[M] ;//存放當前結點指向的下一節點
int w[N];//每個點的分(權值)
int n;
ll f[N];//f[i]表示以i為根節點的連通塊權值和的最大值(dp)
void add(int a,int b){//鄰接表存圖
//建立a->b這條邊,思想是將b結點放入a的鄰接單連結串列裡
//1.存插入值
e[idx]=b;
//2.連線
ne[idx] =h[a];
h[a]=idx++;
}
//dfs計算樹形dp其實是遞迴
void dfs(int a,int father) {
f[a]=w[a];
for(int i=h[a];i!=-1;i=ne[i]){
int j=e[i];
if(j!=father){
//
dfs(j,a);
f[a]+=max(0ll,f[j]);
}
}
}
int main(){
memset(h,-1,sizeof(h)) ;
cin>>n;
for(int i=1;i<=n;i++){
//點從1號開始標
cin>>w[i] ;
}
//鄰接表存圖,鄰接表就是多個單連結串列,每個單連結串列存放與當前點相鄰的點
for(int i=0;i<n-1;i++){//對於樹,n個結點對應n-1條無向邊
int a,b;
cin>>a>>b;
//無向邊就要雙向存
add(a,b);
add(b,a);
}
dfs(1,-1) ;//dfs計算每個結點為根節點的最大權值子樹包括這個根的權值
ll res=0;
for(int i=1;i<=n;i++){
res=max(res,f[i]);//遍歷看哪個為根節點的連通塊權值和最大
}
cout<<res;
return 0;
}
完整程式碼
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int N=1e5+6;//結點數
const int M=2*N;
int w[N] ;//每個結點的評分
int h[N] ;//頭結點
//因為樹是無向圖,所以一條邊存兩遍(a,b)(b,a),所以e[ ],ne[ ]容量開兩遍因為存節點下標
int e[M] ;//存放當前點的下標
int ne[M];//next指標,指向下一個節點
int idx;//當前在第幾個點
ll dp[N];//dp[u]表示以u為根的連通塊最大權值和,樹形dp
int n;//頂點個數
void add(int a,int b) {
//新增a->b這條邊
//利用頭插法,在a頭結點後面插入b
e[idx]=b;//第一步存放b點
//第二步:連線
ne[idx] =h[a];
h[a]=idx++;
}
//樹狀dp,用遞迴dfs
void dfs(int u,int father){
dp[u]=w[u];//以u為根的連通塊,他包含u這個點作為根
for(int i=h[u];i!=-1;i=ne[i]){//遍歷u的所有鄰結點
int j=e[i];
if(j!=father){//防止重複遍歷,所以遍歷鄰結點但不能是他的父節點
dfs(j,u);//遞迴,下一層
dp[u]+=max(0ll,dp[j]);//dp[u]以u為根節點最大連通塊權值和,所以只加上非負的鄰接點
}
}
}
int main(){
memset(h,-1,sizeof(h));//初始化頭結點連結串列
cin>>n;
for(int i=1;i<=n;i++){
cin>>w[i];;//每個結點的權值(評分),注意從1號結點開標
}
//鄰接表建圖,鄰接表就是多個單連結串列,每個單連結串列是存放與當前結點相連的點
for(int i=0;i<n-1;i++){
//有n個頂點的樹擁有n-1條無向邊
int a,b;
cin>>a>>b;
//建立邊存入鄰接表
add(a,b);
add(b,a);
}
//dfs
dfs(1,-1);//從第一個結點開始搜,然後他的父節點是-1
ll ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,dp[i]);
}
cout<<ans;
return 0;
}
核心程式碼
鄰接表存圖
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int N=1e5+6;//結點數
const int M=2*N;
int w[N] ;//每個結點的評分
int h[N] ;//頭結點
//因為樹是無向圖,所以一條邊存兩遍(a,b)(b,a),所以e[ ],ne[ ]容量開兩遍因為存節點下標
int e[M] ;//存放當前點的下標
int ne[M];//next指標,指向下一個節點
int idx;//當前在第幾個點
ll dp[N];//dp[u]表示以u為根的連通塊最大權值和,樹形dp
int n;//頂點個數
void add(int a,int b) {
//新增a->b這條邊
//利用頭插法,在a頭結點後面插入b
e[idx]=b;//第一步存放b點
//第二步:連線
ne[idx] =h[a];
h[a]=idx++;
}
int main(){
memset(h,-1,sizeof(h));//初始化頭結點連結串列
//鄰接表建圖,鄰接表就是多個單連結串列,每個單連結串列是存放與當前結點相連的點
for(int i=0;i<n-1;i++){
//有n個頂點的樹擁有n-1條無向邊
int a,b;
cin>>a>>b;
//建立邊存入鄰接表
add(a,b);
add(b,a);
}
}
樹狀dp+dfs
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int N=1e5+6;//結點數
const int M=2*N;
int w[N] ;//每個結點的評分
int h[N] ;//頭結點
//因為樹是無向圖,所以一條邊存兩遍(a,b)(b,a),所以e[ ],ne[ ]容量開兩遍因為存節點下標
int e[M] ;//存放當前點的下標
int ne[M];//next指標,指向下一個節點
int idx;//當前在第幾個點
ll dp[N];//dp[u]表示以u為根的連通塊最大權值和,樹形dp
int n;//頂點個數
//樹狀dp,用遞迴dfs
void dfs(int u,int father){
dp[u]=w[u];//以u為根的連通塊,他包含u這個點作為根
for(int i=h[u];i!=-1;i=ne[i]){//遍歷u的所有鄰結點
int j=e[i];
if(j!=father){//防止重複遍歷,所以遍歷鄰結點但不能是他的父節點
dfs(j,u);//遞迴,下一層
dp[u]+=max(0ll,dp[j]);//dp[u]以u為根節點最大連通塊權值和,所以只加上非負的鄰接點
}
}
}
int main(){
//dfs
dfs(1,-1);//從第一個結點開始搜,然後他的父節點是-1
ll ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,dp[i]);
}
cout<<ans;
return 0;
}
10.壘骰子
分析程式碼
點數0~5
完整程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=6;
typedef long long int ll;
const int mod=1e9+7;
int a[N][N];//帶限制的矩陣,即係數矩陣
int ops(int x){
if(x>=3)return x-3;
return x+3;
}
//矩陣乘法
void mul(int c[N][N],int d[N][N],int e[N][N]){
static int t[N][N];
memset(t,0,sizeof (t));
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
for(int k=0;k<N;k++){
t[i][j]=(t[i][j]+(ll)d[i][k]*e[k][j])%mod;
}
}
}
memcpy(c,t,sizeof(t));
}
int main(){
int n,m;//n個骰子,m種限制
cin>>n>>m;
//係數矩陣初始化4,就是沒限制
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
a[i][j]=4;
}
}
while(m--){//限制
int x,y;
cin>>x>>y;
x--;y--;//化為0~5點數
//這是下面那個骰子的係數矩陣,如果下面那個骰子上面是x不能轉移到上面那個骰子的下面是y的情況也就是上面那個骰子上面是ops(y)
a[x][ops(y)]=0;
a[y][ops(x)]=0;
}
int f[N][N]={4,4,4,4,4,4};//存結果,初始是隻有一個骰子那麼每個點數做最上面的情況都是4
long long int ans=0;
for(int k=n-1;k;k>>=1){//快速冪,目的計算f*a的n-1次方
if(k&1) mul(f,f,a);//計算a*f
mul(a,a,a);
}
//最上面行就是答案,即用完所有骰子最上面骰子的上面是各個點數的情況數然後求和
for(int i=0;i<N;i++){
ans=(ans+f[0][i])%mod;
}
cout<<ans;
return 0;
}
if(k&1)乘法
乘方
}
int t[N][N];//暫存陣列
memset(t,0,sizeof (t));
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
for(int k=0;k<N;k++){
t[i][j]=(t[i][j]+(ll)d[i][k]*e[k][j])%mod;
}
}
}
memcpy(c,t,sizeof(t));//將t陣列內容放入c
}