Problem A: M1crosoft Exce1
直接的模拟题,代码:
#include<bits/stdc++.h> using namespace std; struct stu { string text; int align; struct stu *f; } p[30][30],*self; int main() { //freopen("in.txt", "r", stdin); int t,n,m,d,k,i,j,flag,b,y; char s[10],ch[300]; char a,x; cin>>t; while(t--) { for(i=0; i<30; i++) { for(j=0; j<30; j++) { p[i][j].text=""; p[i][j].f=&p[i][j]; p[i][j].align=0; } } cin>>n>>m>>d>>k; while(k--) { scanf("%s",s); getchar(); if(strcmp(s,"text")==0) { scanf("%c%d ",&a,&b); fgets(ch,300,stdin); ch[strlen(ch)-1]='\0'; p[a-'A'+1][b].text=ch; } else if(strcmp(s,"align")==0) { scanf("%c%d%s",&a,&b,ch); if(strcmp(ch,"left")==0) { p[a-'A'+1][b].align=0; } else if(strcmp(ch,"right")==0) { p[a-'A'+1][b].align=1; } } else if(strcmp(s,"merge")==0) { scanf("%c%d %c%d",&a,&b,&x,&y); for(i=a; i<=x; i++) { for(j=b; j<=y; j++) { p[i-'A'+1][j].f=&p[x-'A'+1][y]; } } } } for(i=-m-1; i<m*d; i++) { cout<<"-"; } cout<<endl; for(i=1; i<=n;) { flag=0; cout<<"|"; for(j=1; j<=m; j++) { self=p[i][j].f; if(self->text.length()<d) { if(self->align==1) { for(k=d-self->text.length(); k>0; k--) { cout<<" "; } cout<<self->text; } else if(self->align==0) { cout<<self->text; for(k=d-self->text.length(); k>0; k--) { cout<<" "; } } self->text=""; } else { if(self==&p[i][j]) { flag=1; } cout<<self->text.substr(0,d); self->text=self->text.substr(d); } if(j==m||p[i][j].f!=p[i][j+1].f) { cout<<"|"; } else { if(self->text.length()==0) { cout<<" "; } else { cout<<self->text.substr(0,1); self->text=self->text.substr(1); } } } cout<<endl; if(flag==0) { cout<<"-"; for(j=1; j<=m; j++) { if(i==n||p[i][j].f!=p[i+1][j].f) { for(k=0; k<d; k++) { cout<<"-"; } } else { self=p[i][j].f; if(self->text.length()<d) { if(self->align==1) { for(k=d-self->text.length(); k>0; k--) { cout<<" "; } cout<<self->text; } else if(self->align==0) { cout<<self->text; for(k=d-self->text.length(); k>0; k--) { cout<<" "; } } self->text=""; } else { cout<<self->text.substr(0,d); self->text=self->text.substr(d); } } if(i==n||p[i][j].f!=p[i+1][j].f||p[i][j].f!=p[i][j+1].f) { cout<<"-"; } else { self=p[i][j].f; if(self->text.length()==0) { cout<<" "; } else { cout<<self->text.substr(0,1); self->text=self->text.substr(1); } } } cout<<endl; i++; } } cout<<endl; } return 0; }
Problem B: J VS B
题解:简单的博弈题,考虑k>1时一定是yes;k=1时判断n的奇偶
代码:
#include<bits/stdc++.h> using namespace std; int main() { //freopen("test01.in","r",stdin); //freopen("test01.out","w",stdout); int n,k; int T; while(scanf("%d",&T)!=EOF){ while(T--){ scanf("%d%d",&n,&k); if(k>1) printf("yes\n"); else{ if(n%2==0) printf("no\n"); else printf("yes\n"); } } } return 0; }
Problem C: Jinixin Speech
题解:给你n个数,m次询问,每次询问是这样的:
输入 x,将会构造出一个新的序列,这个新的序列b[i]=a[x]-a[i](iSum2输出Keep dis
如果sum1=sum2输出Next time
如果Sum1j的时候
Sum2+=a[x][j]*(j-s[x]) (s[x]<j的时候)
然后扫一遍10个数就好了~
代码:
#include<bits/stdc++.h> using namespace std; long long a[100005][11]; int main() { long long i,j,n,m,x,tmp,A,B; string s; while(~scanf("%lld%lld",&n,&m)) { memset(a,0,sizeof(a)); cin>>s; for(i=0;i<s.size();i++) { if(i!=0) for(j=0;j<10;j++) a[i][j]=a[i-1][j]; a[i][s[i]-'0']++; } while(m--) { scanf("%lld",&x); tmp=s[x-1]-'0'; A=B=0; for(i=0;i<10;i++) { if(i<tmp) A+=(tmp-i)*a[x-1][i]; else if(i>tmp) B+=(i-tmp)*a[x-1][i]; } if(A==B) printf("Next time\n"); else if(A>B) printf("Keep some distance from me\n"); else printf("I agree\n"); } } return 0; }
Problem D: Group Sum
题解:
题意:
给定一个数M,从1~9这9个数中选出M个不同的数,组成一个集合。
当集合中所有元素之和等于N时,输出该集合,要求找到所有满足条件的集合。
注:集合之间从小到大排序,集合内元素也要从小到大排序。
想法:
拿到题,因为集合中的元素来自1~9,且要求有序输出,所以很容易想到用循环嵌套来做,但因为题中M不确定,故用M个循环解决本题可能比较麻烦。循环与递归在某种程度上是可以相互转换的,故我们通过递归来思考本题。
vector<int> minums; void dfs(int i,int m) { if(m==(int)minums.size()) { //找到了一个长度为m的集合 return; } for(i++;i<=9;i++) { minums.push_back(i);//将i加入minums集合末尾 dfs(i,m); minums.pop_back();//将minums集合末尾的元素删除 } } 调用:dfs(0,m); 通过上述代码可以找到所有长度为m的集合。 minums集合中的元素满足从小到大的顺序,且找到的长度为m的集合的先后顺序也满足从小到大。 下面我们只要着手判断该集合内所有元素之和是否等于n?如果等于n则把该集合再存储进一个大集合即可。
vector<int> minums; vector<vector<int>> nums;//大集合 void dfs(int i,int m,int n) { if(n<0)//集合中元素之和已经超过n { return;//返回 } if(m==(int)minums.size())//找到了一个长度为m的集合 { if(n==0)//如果集合中所有元素之和等于n,则该集合minums符合要求 { nums.push_back(minums);//将minums存储到集合nums中 } return;//返回 } for(i++;i<=9;i++) { minums.push_back(i);//将i加入minums集合末尾 dfs(i,m,n-i); minums.pop_back();//将minums集合末尾的元素删除 } } 调用:dfs(0,m,n); nums集合即为最终答案。
代码:
#include<iostream> #include<vector> using namespace std; vector<int> minums; vector<vector<int>> nums; void dfs(int i,int k,int n) { if(n<0) { return; } if(k==(int)minums.size()) { if(n==0) { nums.push_back(minums); } return; } for(i++;i<=9;i++) { minums.push_back(i); dfs(i,k,n-i); minums.pop_back(); } } int main() { int k,n,i,j; while(~scanf("%d%d",&k,&n)) { nums.clear(); minums.clear(); dfs(0,k,n); cout<<"["; for(i=0;i<(int)nums.size();i++) { cout<<"["; for(j=0;j<k;j++) { printf(j==k-1?"%d":"%d,",nums[i][j]); } cout<<"]"; if(i!=(int)nums.size()-1) { cout<<","; } } cout<<"]"<<endl; } return 0; }
Problem E: Binary Tree
题意:
按层序给你一棵二叉树各节点值的序列(空节点值为null),要求建立该二叉树,并判断该二叉树是否具有对称性。
如果具有对称性,输出1。
如果不具有对称性,输出0,并输出该二叉树的先序遍历序列。
想法:
本题是模拟题,涉及“字符串处理”,“二叉树建树”,“先序遍历”。
注1:给定的序列是“A B C D ”这样的形式,字母表示节点的值,节点值后面一定有一个空格。
注2:题中说明“节点值为整数”,但大家需要考虑到负整数的情况!
**************************************************************************************************** //数据结构定义 struct TreeNode { int val; TreeNode *left,*right; }; **************************************************************************************************** //将读入的序列转换为二叉树 TreeNode* deserialize(string data) { TreeNode *root,*head,*pre; queue<TreeNode *> p; int i=0,j=0,flag=1;//flag为0表示节点为空;为1表示正数;为-1表示负数。 //由于需要知道所建树的根节点地址,故单独先读第一个数! while(data[i]!=' '&&i<data.size())//一直向下遍历,直到遇到空格或字符串结束 { if(data[i]=='n')//读到“n”,跳过“null ” { i+=4;//这里不是3是因为null后跟一空格 flag=0; break;//该节点为空,直接跳出 } else if(data[i]=='-')//读到“-”,后面所跟数是负的! { flag=-1;//标记为负的! i++; } j=j*10+data[i++]-'0';//将字符串变为数字 } if(!flag)//当读到null时,树的根节点不存在 { return NULL; } else { head=(TreeNode *)malloc(sizeof(TreeNode)); head->val=j*flag;//flag表示正负! head->left=head->right=NULL; p.push(head);//压入队列 } while(!p.empty()) { pre=p.front();//从队列中读出一个节点作为根节点 p.pop(); j=0;flag=1;i++; while(data[i]!=' '&&i<data.size())//读入第一个数,具体过程同“上方代码” { if(data[i]=='n') { i+=4; flag=0; break; } else if(data[i]=='-') { flag=-1; i++; } j=j*10+data[i++]-'0'; } if(!flag&&i<data.size())//当读到null时,该节点不存在。即根节点的左子树不存在 { pre->left=NULL; } else if(i<data.size()) { root=(TreeNode *)malloc(sizeof(TreeNode)); root->val=j*flag; root->left=root->right=NULL; pre->left=root;//根的左孩子即为该数所在节点 p.push(root);//将该数所在节点压入队列 } j=0;flag=1;i++; while(data[i]!=' '&&i<data.size())//读入第二个数,具体过程同“上方代码” { if(data[i]=='n') { i+=4; flag=0; break; } else if(data[i]=='-') { flag=-1; i++; } j=j*10+data[i++]-'0'; } if(!flag&&i<data.size())//当读到null时,该节点不存在。即根节点的右子树不存在 { pre->right=NULL; } else if(i<data.size()) { root=(TreeNode *)malloc(sizeof(TreeNode)); root->val=j*flag; root->left=root->right=NULL; pre->right=root;//根的右孩子即为该数所在节点 p.push(root);//将该数所在节点压入队列 } } return head;//返回所建树根节点的地址 } 调用:deserialize(传入序列); **************************************************************************************************** //判断序列是否具有对称性 bool flag; void dfs(struct TreeNode *Tleft,struct TreeNode *Tright) { if(!flag) { return; } if(Tleft->val!=Tright->val)//左子树和右子树根节点值不相等,不对称! { flag=false; return; } if(Tleft->right&&Tright->left)//“左子树的右子树”和“右子树的左子树”都存在 { dfs(Tleft->right,Tright->left);//递归,进一步判断“左子树的右子树和右子树的左子树” } else if(!Tleft->right&&!Tright->left)//“左子树的右子树”和“右子树的左子树”都不存在,对称 { ; } else//“左子树的右子树”或“右子树的左子树”不存在,不对称! { flag=false; return; } if(Tleft->left&&Tright->right)//同理判断“左子树的左子树和右子树的右子树” { dfs(Tleft->left,Tright->right); } else if(!Tleft->left&&!Tright->right) { ; } else { flag=false; return; } } bool isSymmetric(struct TreeNode* root) { flag=true; if(root) { if(root->right&&root->left)//树的根节点有左子树和右子树 { dfs(root->left,root->right);//进一步判断树的左右子树情况 } else if(!root->right&&!root->left)//树的根节点没有左子树和右子树,对称 { ; } else//树的根节点没有左子树或右子树,一定不对称! { flag=false; } } return flag; } 调用:isSymmetric(传入二叉树根节点地址); **************************************************************************************************** //先序遍历二叉树 void tlr(struct TreeNode* root) { if(root) { //操作root->val的语句写在这里,本题为“cout<<root->val;” tlr(root->left); tlr(root->right); } } 调用:tlr(传入二叉树根节点地址);
代码:
#include<iostream> #include<cstdio> #include<queue> using namespace std; struct TreeNode { int val; struct TreeNode *left,*right; }; int flag; TreeNode* init(string data) { TreeNode *root,*head,*pre; queue<TreeNode *> p; int i=0,j=0,flak=1; while(data[i]!=' '&&i<data.size()) { if(data[i]=='n') { i+=4; flak=0; break; } else if(data[i]=='-') { flak=-1; i++; } j=j*10+data[i++]-'0'; } if(!flak) { return NULL; } else { head=(TreeNode *)malloc(sizeof(TreeNode)); head->val=j*flak; head->left=head->right=NULL; p.push(head); } while(!p.empty()) { pre=p.front(); p.pop(); j=0;flak=1;i++; while(data[i]!=' '&&i<data.size()) { if(data[i]=='n') { i+=4; flak=0; break; } else if(data[i]=='-') { flak=-1; i++; } j=j*10+data[i++]-'0'; } if(!flak&&i<data.size()) { pre->left=NULL; } else if(i<data.size()) { root=(TreeNode *)malloc(sizeof(TreeNode)); root->val=j*flak; root->left=root->right=NULL; pre->left=root; p.push(root); } j=0;flak=1;i++; while(data[i]!=' '&&i<data.size()) { if(data[i]=='n') { i+=4; flak=0; break; } else if(data[i]=='-') { flak=-1; i++; } j=j*10+data[i++]-'0'; } if(!flak&&i<data.size()) { pre->right=NULL; } else if(i<data.size()) { root=(TreeNode *)malloc(sizeof(TreeNode)); root->val=j*flak; root->left=root->right=NULL; pre->right=root; p.push(root); } } return head; } void dfs(struct TreeNode *Tleft,struct TreeNode *Tright) { if(!flag) { return; } if(Tleft->val!=Tright->val) { flag=false; return; } if(Tleft->right&&Tright->left) { dfs(Tleft->right,Tright->left); } else if(!Tleft->right&&!Tright->left) { ; } else { flag=false; return; } if(Tleft->left&&Tright->right) { dfs(Tleft->left,Tright->right); } else if(!Tleft->left&&!Tright->right) { ; } else { flag=false; return; } } int isSymmetric(struct TreeNode* root) { flag=1; if(root) { if(root->right&&root->left) { dfs(root->left,root->right); } else if(!root->right&&!root->left) { ; } else { flag=0; } } return flag; } void tlr(struct TreeNode *root) { if(!root) { return; } cout<<root->val; tlr(root->left); tlr(root->right); } int main() { string s; int num; struct TreeNode *lead; while(getline(cin,s)) { lead=init(s); num=isSymmetric(lead); cout<<num<<endl; if(!num) { tlr(lead); cout<<endl; } } return 0; }
Problem F: The Clock of Station
题解:简单题代码:
#include<stdio.h> int main() { int T; scanf("%d",&T); while(T--){ int x,y,z; scanf("%d%d%d",&x,&y,&z); printf("%d\n",(x+y)*z); } return 0; }
Problem G: Count beans will be crazy
题解:(这是一个小学奥数改编的题目)由题意可得本题即求最小公倍数,需考虑到long long,还有直接打出来也是可以的
代码:
#include<stdio.h> long long gcd(long long n,long long m) { long long a=n,b=m,r=a%b; while(r) { a=b; b=r; r=a%b; } return n/b*m; } int main() { int n,i; long long f[45]; f[2]=2; for(i=3;i<=40;i++) { f[i]=gcd(f[i-1],i); } while(~scanf("%d",&n)) { printf("%lld\n",f[n]-1); } return 0; }
Problem H: Math
题解:此题数据有点虚了,换一种思路可以直接搞。提供本来自己思路的代码
代码:
#include <bits/stdc++.h> using namespace std; int T,n,k; int p[]={2,3,5,7,11,13,17,19,23,29,31}; int sum[11],s[11]; void solve() { memset(sum,0,sizeof(sum)); memset(s,0,sizeof(s)); if(n<2) return; int i,j; for(i=0;i<11;++i) { j=n; while(j) { sum[i]+=(j/=p[i]); } } } int calc() { if(n<2) return 0; int ans=0x7fffffff; int i,j; for(i=0;i<11;++i) { while(!(k%p[i])) { k/=p[i]; ++s[i]; } } for(i=0;i<11;++i) { if(!s[i]) continue; ans=min(ans,sum[i]/s[i]); } return ans; } int main() { //freopen("test01.in","r",stdin); //freopen("test01.out","w",stdout); scanf("%d",&T); while(T--) { scanf("%d%d",&n,&k); //cin>>n>>k; solve(); printf("%d\n",calc()); //cout<<calc()<<endl; } return 0; }
Problem I: Jinixin -> Mosu
题意:
在一个二维数组中寻找最长的递增序列长度,该二维数组长度最大可至1000*1000。
想法:
根据题意,大致确定这是一道搜索题,由于寻找的是“最长递增序列长度”,判断应该用迷宫类型的dfs,故直接套模板。
const int N=1000; int p[N][N],vis[N][N],dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; int max,n,m; void dfs(int x,int y,int t)//迷宫类dfs模板,t为现在“递增序列”的长度 { int i,a,b; max=max>t?max:t;//更新max,max为目前“最长递增序列长度” for(i=0;i<4;i++) { a=x+dir[i][0];//根据所处X坐标,产生前进方向的X坐标 b=y+dir[i][1];//根据所处Y坐标,产生前进方向的Y坐标 if(a>=0&&a<n&&b>=0&&b<m&&!vis[a][b]&&p[a][b]>p[x][y])//判断前进方向坐标是否合法,是否未走过,是否递增 { vis[a][b]=1;//p[a][b]已经走过 dfs(a,b,t+1); vis[a][b]=0;//p[a][b]重新标记未走过 } } } int longestIncreaseRoute() { int i,j; max=0; memset(vis,0,sizeof(vis));//vis用于判断该位置是否已经走过 scanf("%d%d",&n,&m); for(i=0;i<n;i++) { for(j=0;j<m;j++) { scanf("%d",&p[i][j]);//输入二维数组 } } for(i=0;i<n;i++) { for(j=0;j<m;j++) { dfs(i,j,1);//对二维数组每一个位置进行搜索,找出从该位置出发的“最长递增序列长度” } } return max;//返回max,max为“最长递增序列长度” } 调用:longestIncreaseRoute(); 上述方法处理大小为100*100已经费劲了,更别说1000*1000,故我们要想方法提高时效:剪枝or记忆化,下面使用记忆化解决本题。
注:寻找“最长递增序列长度”和寻找“最长递减序列长度”是等价的! const int N=1000; int p[N][N],vis[N][N],store[N][N],dir[4][3]={{-1,0},{1,0},{0,-1},{0,1}};//store数组用于记忆化 int dfs(int x,int y) { int i,a,b,sum=1;//sum为从该位置出发的“最长递减序列长度” for(i=0;i<4;i++) { a=x+dir[i][0]; b=y+dir[i][1]; dir[i][2]=1; if(a>=0&&a<n&&b>=0&&b<m&&!vis[a][b]&&p[a][b]<p[x][y]) { if(store[a][b])//以前搜索过从该位置出发的“最长递减序列长度”,不再重复劳动 { dir[i][2]=store[a][b]+1; } else { vis[a][b]=1; dir[i][2]=dfs(a,b)+1;//dir[i][2]记录从“该位置i方向”出发的“最长递减序列长度” vis[a][b]=0; } } sum=sum>dir[i][2]?sum:dir[i][2];//四个方向中选取最大的值 } store[x][y]=sum;//记忆化,从该位置(x,y)出发的“最长递减序列长度” return sum; } int longestIncreaseRoute() { int i,j; int max=0; memset(vis,0,sizeof(vis)); memset(store,0,sizeof(store)); scanf("%d%d",&n,&m); for(i=0;i<n;i++) { for(j=0;j<m;j++) { scanf("%d",&p[i][j]); } } for(i=0;i<n;i++) { for(j=0;j<m;j++) { if(!store[i][j])//如果之前已经搜索过从该位置出发的“最长递减序列长度”,则不再搜索该位置 { vis[i][j]=1; dfs(i,j); vis[i][j]=0; } } } for(i=0;i<n;i++) { for(j=0;j<m;j++) { max=max>store[i][j]?max:store[i][j];//找出“最长递减序列长度” } } return max; } 调用:longestIncreaseRoute(); “迷宫类dfs+记忆化”可以高效的解决本题。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int M=1005; int p[M][M],vis[M][M],store[M][M],dir[4][3]={{-1,0},{1,0},{0,-1},{0,1}}; int n,m; int dfs(int x,int y) { int i,a,b,sum=1; for(i=0;i<4;i++) { a=x+dir[i][0]; b=y+dir[i][1]; dir[i][2]=1; if(a>=0&&a<n&&b>=0&&b<m&&!vis[a][b]&&p[a][b]<p[x][y]) { if(store[a][b]) { dir[i][2]=store[a][b]+1; } else { vis[a][b]=1; dir[i][2]=dfs(a,b)+1; vis[a][b]=0; } } sum=sum>dir[i][2]?sum:dir[i][2]; } store[x][y]=sum; return sum; } int path() { int i,j,max=0; for(i=0;i<n;i++) { for(j=0;j<m;j++) { if(!store[i][j]) { vis[i][j]=1; dfs(i,j); vis[i][j]=0; } } } for(i=0;i<n;i++) { for(j=0;j<m;j++) { max=max>store[i][j]?max:store[i][j]; } } return max; } int main() { //freopen("test1.in","r",stdin); //freopen("test1.out","w",stdout); int i,j; while(~scanf("%d%d",&n,&m)) { memset(vis,0,sizeof(vis)); memset(store,0,sizeof(store)); for(i=0;i<n;i++) { for(j=0;j<m;j++) { scanf("%d",&p[i][j]); } } printf("%d\n",path()); } return 0; }
Problem J: Jinixin's password
题解:首先我们判断是否能由n个数构成m。
数据比如 3 0,1 19这种,就不能构成
然后我们就可以贪心了~
最小的数,肯定是由1000000000这种,然后从低位开始增加,直到达到m为止
而最大的数,则是由9999999999这种,从低位到高位,逐渐减小,直到变成m
比如 4 27这组数据
首先贪心最小的:
目前的数 目前的sum
1000 1
1009 10
1099 19
1899 27
贪心最大的:
目前的数 目前的sum
9999 36
9990 27
所以输出1899 9990
代码:
#include<iostream> #include<stdio.h> using namespace std; int flag; int n,m; int Min[120]; int Max[120]; void getmin() { int sum = 0; for(int i=1;i<=n;i++) { if(i==1)Min[i]=1; else Min[i]=0; sum += Min[i]; } sum = m - sum; for(int i=n;i>=1;i--) { int T = min(sum,9-Min[i]); sum -= T; Min[i] += T; } if(Min[1]==0)flag = 1; } void getmax() { int sum = 0; for(int i=1;i<=n;i++) { Max[i]=9; sum+=Max[i]; } sum = sum - m; for(int i=n;i>=1;i--) { int T = min(sum,Max[i]); sum-=T; Max[i]-=T; } if(Max[1]==0)flag = 1; } int main() { int t; scanf("%d",&t); for(int cas=1;cas<=t;cas++) { scanf("%d%d",&n,&m); flag = 0; if(n==1&&m==0) { printf("0 0\n"); continue; } if(n*9<m) { printf("-1 -1\n"); continue; } getmin(),getmax(); if(flag) { printf("-1 -1\n"); continue; } for(int i=1;i<=n;i++) printf("%d",Min[i]); printf(" "); for(int i=1;i<=n;i++) printf("%d",Max[i]); printf("\n"); } }