2014年蓝桥杯整理
神奇的算式
由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如:
6 x 210 = 1260
8 x 473 = 3784
27 x 81 = 2187
1.枚举,排序,比较
#include<iostream> #include<sstream> #include<algorithm> using namespace std; int ans; void i2s(long long x,string &basic){//字符串转成数字 stringstream ss; ss<<x; ss>>basic; } bool check(long long src,long long r){ string src_str,r_str; i2s(r,r_str); i2s(src,src_str); sort(r_str.begin(),r_str.end()); sort(src_str.begin(),src_str.end());//排序比较 if(r_str==src_str) return true; return false; } int main(){ for(int i=1;i<10;i++){ for(int j=0;j<10;j++){ if(i!=j) for(int k=0;k<10;k++) if(k!=j&&k!=i) for(int l=0;l<10;l++) if(l!=j&&l!=i&&l!=k) { long long src=i*1000+j*100+k*10+l;//ijkl四位数 // if(i!=0){ long long r1=i*(j*100+k*10+l); if(check(src,r1)) cout<<i<<"*"<<j<<k<<l<<"="<<r1<<endl; } if(k!=0) { long long r2=(i*10+j)*(k*10+l); if((i*10+j)<(k*10+l)&&check(src,r2)) cout<<i<<j<<"*"<<k<<l<<"="<<r2<<endl; } /*if(l!=0){ long long r3=(i*100+j*10+k)*l; if(check(src,r3)) cout<<i<<j<<k<<"*"<<l<<"="<<r3<<endl; }*/ } } } return 0; }
扑克序列
A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。
要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。
1.全排列+检查
#include<iostream> #include<algorithm> #include<string> using namespace std; bool check(const string &b); int main(){ string s="223344AA"; do{ if(check(s)) cout<<s<<endl; }while(next_permutation(s.begin(),s.end())); return 0; } bool check(const string &b){ if(b.rfind('A')-b.find('A')==2&& b.rfind('2')-b.find('2')==3&& b.rfind('3')-b.find('3')==4&& b.rfind('4')-b.find('4')==5) return true; return false; }
蚂蚁感冒
长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。
第一行输入一个整数n (1 < n < 50), 表示蚂蚁的总数。 接着的一行是n个用空格分开的整数 Xi (-100 < Xi < 100), Xi的绝对值,表示蚂蚁离开杆子左边端点的距离。正值表示头朝右,负值表示头朝左,数据中不会出现0值,也不会出现两只蚂蚁占用同一位置。其中,第一个数据代表的蚂蚁感冒了。
1.这不是模拟
2.突破思维禁锢
#include<iostream> using namespace std; int arr[51]; int main(){ int n; cin>>n; for(int i=0;i<n;i++){ cin>>arr[i]; } int x=arr[0]; if(x>0){ int ans=1; for(int i=0;i<n;i++){ if(arr[i]<0&&-arr[i]>x) ans++; } if(ans!=1)//有从右到左的 { for(int i=0;i<n;i++){ if(arr[i]>0&&arr[i]<x) //紧随其后的 ans++; } } cout<<ans<<endl; } if(x<0){ int ans=1; for(int i=0;i<n;i++){ if(arr[i]>0&&arr[i]<-x) ans++; } if(ans!=1){ for(int i=0;i<n;i++){ if(arr[i]<0&&-arr[i]>-x) ans++; } } cout<<ans<<endl; } return 0; }
斐波那契
1.快速斐波那契
2.快速乘法
#include<iostream>//快速斐波那契 #include<cstring> //f(x)=f(x+1)-f(x-1) 所以和等价于f(n+2)-1 using namespace std; typedef long long ll; ll n,m,mod; /*void solve1(){ ll a=1,b=1; if(m>=n+2){ for(int i=3;i<=n+2;i++){ ll t=a; a=b; b+=t; } cout<<b%mod-1; } else { ll fibm,fibn_2=0; for(int i=3;i<=n+2;i++){ ll t=a; a=b; b+=t; if(i==m) fibm=b; } fibn_2=b; cout<<fibn_2%fibm%mod-1; } }*/ class M{ public: ll data[2][2]; M(){memset(data,0,sizeof(data));} }; //快速乘法 ll mm(ll a,ll b,ll mod){ if(a>b){ ll t=a; a=b; b=t; } ll x=0; while (b!=0){ if((b&1)==1) x=(x+a)%mod; a=a*2; a%=mod; b>>=1; } return x; } ll mm(ll a,ll b){ if(a>b){ ll t=a; a=b; b=t; } ll x=0; while (b!=0){ if((b&1)==1) x=(x+a); a=a*2; b>>=1; } return x; } //将两个2*2的矩阵相乘 M *mul(M *m1,M *m2,ll mod){ M *ans=new M(); ans->data[0][0]=(mm(m1->data[0][0],m2->data[0][0],mod)+mm(m1->data[0][1],m2->data[1][0],mod))%mod; ans->data[0][1]=(mm(m1->data[0][0],m2->data[0][1],mod)+mm(m1->data[0][1],m2->data[1][1],mod))%mod; ans->data[1][0]=(mm(m1->data[1][0],m2->data[0][0],mod)+mm(m1->data[1][1],m2->data[1][0],mod))%mod; ans->data[1][1]=(mm(m1->data[1][0],m2->data[0][1],mod)+mm(m1->data[1][1],m2->data[1][1],mod))%mod; return ans; } M *mul(M *m1,M *m2){ M *ans=new M(); ans->data[0][0]=(mm(m1->data[0][0],m2->data[0][0])+mm(m1->data[0][1],m2->data[1][0])); ans->data[0][1]=(mm(m1->data[0][0],m2->data[0][1])+mm(m1->data[0][1],m2->data[1][1])); ans->data[1][0]=(mm(m1->data[1][0],m2->data[0][0])+mm(m1->data[1][1],m2->data[1][0])); ans->data[1][1]=(mm(m1->data[1][0],m2->data[0][1])+mm(m1->data[1][1],m2->data[1][1])); return ans; } //m的n次幂 M *mpow(M *m,int n,ll mod){ M *E =new M();//单位矩阵 E->data[0][0]=1; E->data[1][1]=1; while(n!=0){ if(n&1==1) { E=mul(E,m,mod); } m=mul(m,m,mod);//按平方倍增 n>>=1; } return E; } M *mpow(M *m,int n){ M *E =new M();//单位矩阵 E->data[0][0]=1; E->data[1][1]=1; while(n!=0){ if(n&1==1) { E=mul(E,m); } m=mul(m,m);//按平方倍增 n>>=1; } return E; } ll fib(ll i,ll mod){ M *A=new M(); A->data[0][0]=1; A->data[0][1]=1; M *B =new M(); B->data[0][0]=1; B->data[0][1]=1; B->data[1][0]=1; M *ans=mul(A,mpow(B,i-2,mod),mod); return ans->data[0][0]; } ll fib(ll i){ M *A=new M(); A->data[0][0]=1; A->data[0][1]=1; M *B =new M(); B->data[0][0]=1; B->data[0][1]=1; B->data[1][0]=1; M *ans=mul(A,mpow(B,i-2)); return ans->data[0][0]; } void solve2(){ if(m>=n+2){ cout<<fib(n+2,mod)-1; } else { //cout<<(fib(m-1)*(fib(n+2-m)%fib(m)))%fib(m)%mod-1<<" "; //cout<<fib(m)<<endl; cout<<fib(n+2,fib(m))%mod-1; } } int main(){ cin>>n>>m>>mod; // solve1(); //for(int i=3;i<10;i++) //cout<<fib(i,mod)<<endl; solve2(); return 0; }
波动数列
1 3 0 2 -1 1 -2 …
这个数列中后一项总是比前一项增加2或者减少3。
栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加a或者减少b的整数数列可能有多少种呢?
输入的第一行包含四个整数 n s a b,含义如前面说述
输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以100000007的余数
/* dp(i,j)表示从集合U(假设集合中元素从小到大排列) 中前 i 个数中选择,使得和为 j 总共有几种选择 当 i > j 时, 此时第 i 个元素不可以选 (因为选了的话元素之和肯定大于 j) dp( i, j ) = dp( i-1, j ) 当 i <= j 时, 第 i 个元素要么选, 要么不选 dp( i, j ) = dp( i-1, j) + dp( i-1, j- i ) */ #include<iostream>// nx+(n(n-1)/2)a==s #include<vector> #include<cstring> using namespace std; int n,s,a,b; long long ans=0; const int MOD=100000007; void dp2(){ int t=n*(n-1)/2; int dp[2][t+1];//滚动数组 memset(dp,0,sizeof(dp)); dp[0][0]=1; dp[1][0]=1; /*for(int i=0;i<n;i++){ dp[i][0]=1; }*/ int row=0; for(int i=1;i<n;i++){ row=1-row; for(int j=1;j<=i*(i+1)/2;j++){ if(i>j) dp[row][j]=dp[1-row][j]; else dp[row][j]=dp[1-row][j]+dp[1-row][j-i]; } } for(int ta=0;ta<=t;ta++) { if((s-ta*a+(t-ta)*b)%n==0);//a的个数与b的个数 ans+=dp[row][ta]; } cout<<ans<<endl; } /*void dfs(int x,int cnt,int sum,vector<int> path){ if(cnt==n){ if(sum==s) { ans++; for(int i=0;i<path.size();i++) cout<<path[i]<<" "; cout<<endl; } if(ans>MOD) ans%=MOD; return; } path.push_back(x+a); dfs(x+a,cnt+1,sum+x+a,path); path.erase(path.end()-1); path.push_back(x-b); dfs(x-b,cnt+1,sum+x-b,path); }*/ /*void solve2(){ int t=n*(n-1)/2; int x; int x1=(s-a*n*(n-1)/2)/n; int x2=(s+b*n*(n-1)/2)/n; //枚举首项 for(x=x1;x<=x2;x++){ //对x进行初步检测 for(int tA=0;tA<=t;tA++) { long long cal=x*n+tA*a-(t-tA)*b; if(cal==s){ vector<int> path;//观察中间项 path.push_back(x); dfs(x,1,x,path); } } } }*/ int main(){ cin>>n>>s>>a>>b;//n个数,s总和 //solve2(); dp2(); //cout<<ans<<endl; return 0; } //动态规划经典题
一维数组解法
#include<iostream> using namespace std; #define Mod 100000007 typedef long long ll; ll n,s,a,b; ll ans; int dp[1000*1000];//一维数组 void dp3(){ int t=n*(n-1)/2; dp[0]=1; for(int i=1;i<n;i++) for(int j=i*(i+1)/2;j>=i;j--) dp[j]=(dp[j]+dp[j-i])%Mod; for(ll ta=0;ta<=t;ta++){ if((s-ta*a+(t-ta)*b)%n==0) (ans+=dp[ta])%=Mod; } cout<<ans<<endl; } int main(){ cin>>n>>s>>a>>b; dp3(); return 0; }
地宫取宝
X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。小明被带到地宫的入口,国王要求他只能向右或向下行走。走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)
接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值
1.记忆型搜索
2.剪枝
#include<iostream> #include<cstring> using namespace std; const int mod=1000000007; int n,m,k; int data[50][50]; int cache[50][50][14][13];//记忆型搜索 //long long ans; /*void dfs(int x,int y,int max,int cnt){ if(x==n||y==m) return; int cur=data[x][y]; if(x==n-1&&y==m-1){ if(cnt==k||(cnt==k-1&&cur>max)){ ans++; if(ans>mod) ans%=mod; } } if(cur>max){//取物品 dfs(x,y+1,cur,cnt+1); dfs(x+1,y,cur,cnt+1); } dfs(x,y+1,max,cnt); dfs(x+1,y,max,cnt); } */ long long dfs2(int x,int y,int max,int cnt){//cnt是手上宝物数目 //查缓存 if(cache[x][y][max+1][cnt]!=-1) return cache[x][y][max+1][cnt]; if(x==n||y==m||cnt>k) return 0; long long ans=0; int cur=data[x][y];//当前宝贝价值 if(x==n-1&&y==m-1){//出口 if(cnt==k||(cnt==k-1&&cur>max)){ ans++; if(ans>mod) ans%=mod; } return ans; } if(cur>max){//取物品 ans+=dfs2(x,y+1,cur,cnt+1); ans+=dfs2(x+1,y,cur,cnt+1); } ans+=dfs2(x,y+1,max,cnt); ans+=dfs2(x+1,y,max,cnt); cache[x][y][max+1][cnt]=ans%mod;//记录 return ans%mod; } int main(){ cin>>n>>m>>k; memset(cache,-1,sizeof(cache)); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cin>>data[i][j]; } } cout<<dfs2(0,0,-1,0); return 0; }
- 点赞
- 收藏
- 分享
- 文章举报
- 蓝桥杯2014年及之前真题及答案整理
- 蓝桥杯2014年以前JAVA历年真题及答案整理——求和公式
- 2014年第五届蓝桥杯预赛题目JAVA软件开发高职高专组2
- 2014年第五届蓝桥杯省赛C++B组——1、啤酒和饮料
- 蓝桥杯 幂一矩阵 2014年JavaB组决赛第5题
- 蓝桥杯 排列序数 2014年JavaB组决赛第4题
- 2014年蓝桥杯B组初赛(第五届)
- 2014年第五届蓝桥杯决赛C组题目 第四题 标题:拼接平方数
- 【知识整理|数论】蓝桥杯——买不到的数目
- 【蓝桥杯】2014年第五届蓝桥杯省赛真题-Java语言B组-2-(C++B组题2)切面条
- 【蓝桥杯题目分析】2014年第五届——第三题:李白打酒
- 2014年第五届蓝桥杯试题(Java本科B组)
- 蓝桥杯2014年以前JAVA历年真题及答案整理——Excel地址转换
- 蓝桥杯2014年以前JAVA历年真题及答案整理——区间k大数查询
- 蓝桥杯2014年以前JAVA历年真题及答案整理——实数输出
- 2014年蓝桥杯预赛 C/C++本科B组 解题报告 史丰收速算
- 2014年第五届蓝桥杯预赛题目JAVA软件开发高职高专组3
- 六角填数,蓝桥杯2014年第7题
- 2014年第五届蓝桥杯省赛C++B组——2、切面条
- 2015蓝桥杯省赛整理7-8