TZOJ 挑战题库随机训练11

点击题号跳转

A3604 B5608 C5385 D5003 E2527

F2108 G4712 H3993 I1892 J3842

A.The Table回到顶部

题意

n行m列,问哪一列乘积最大,相同输出m大的,n<=1000,m<=20

题解

曾经做过(07G),大数相乘处理一下就行了,复杂度O(nm)

代码

 1 import java.math.BigInteger;
 2 import java.util.*;
 3 
 4 public class Main {
 5 
 6     public static void main(String[] args) {
 7 
 8         BigInteger[] big = new BigInteger[25];
 9 
10         Scanner sc = new Scanner(System.in);
11         while(sc.hasNext()) {
12             int m = sc.nextInt();
13             int n = sc.nextInt();
14             BigInteger b;
15             for (int i = 1; i <= m; i++)
16                 big[i] = BigInteger.ONE;
17             for (int i = 1; i <= n; i++) {
18                 for (int j = 1; j <= m; j++) {
19                     b = sc.nextBigInteger();
20                     big[j] = big[j].multiply(b);
21                 }
22             }
23             int id = 1;
24             BigInteger maxx = big[1];
25             for (int i = 2; i <= m; i++) {
26                 //System.out.println(maxx.compareTo(big[i]));
27                 if (maxx.compareTo(big[i]) <= 0) {
28                     maxx = big[i];
29                     id = i;
30                 }
31             }
32             System.out.println(id);
33         }
34     }
35 }
A

B.单身狗沙漠逃生回到顶部

题意

每走x公里路后,单身狗就要消耗x份食物(x为大于0的分数)。单身狗共准备了n份食物,但他身上最多背负m份食物(n%m为0,而且n/m<11)。如果食物可以在路边存放,为保证能原路返回出发点,单身狗最远能进入沙漠多少公里?

题解

一共走m/n次,第一次(来回)m/2,第二次m/4,以此类推,复杂度O(m/n)

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main(){
 5     int n,m;
 6     while(cin>>n>>m,n||m){
 7         int s=0,x=2*2520;
 8         for(int i=1;i<=n/m;i++)s+=m*(2520/i);
 9         int gc=__gcd(s,x);
10         cout<<s/gc<<'/'<<x/gc<<endl;
11     }
12     return 0;
13 }
B

C.树的遍历回到顶部

题意

给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数,n<=30

题解

后序(左右根),中序(左根右)

递归建树,后序第一个节点为根,然后在中序找到这个根,左右子树分开,复杂度O(n)

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=1005;
 5 int a[N],b[N];
 6 vector<int>G[35];
 7 void build(int L1,int R1,int L2,int R2,int dep){
 8     if(L1>R1)return;
 9     G[dep].push_back(a[R1]);
10     for(int i=L2;i<=R2;i++)if(a[R1]==b[i]){
11         build(L1,L1-1-L2+i,L2,i-1,dep+1);
12         build(R1-R2+i,R1-1,i+1,R2,dep+1);
13     }
14 }
15 int main(){
16     int n;scanf("%d",&n);
17     for(int i=1;i<=n;i++)cin>>a[i];
18     for(int i=1;i<=n;i++)cin>>b[i];
19     build(1,n,1,n,0);
20     int out=0;
21     for(int i=0;i<30;i++)for(int j=0;j<G[i].size();j++){
22         if(out)cout<<' ';
23         cout<<G[i][j];out=1;
24     }
25     return 0;
26 }
C

D.Convert QWERTY to Dvorak回到顶部

题意

给一串键盘A要求输出键盘B,len<=100

题解

对应映射存起来,再处理,复杂度O(70len)

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 string a="-=_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;'ASDFGHJKL:"zxcvbnm,./ZXCVBNM<>?";
 5 string b="[]{}',.pyfgcrl/="<>PYFGCRL?+aoeuidhtns-AOEUIDHTNS_;qjkxbmwvz:QJKXBMWVZ";
 6 int main(){
 7     string s;
 8     while(getline(cin,s)){
 9         for(int i=0;s[i];i++){
10             bool f=0;
11             for(int j=0;a[j];j++)
12                 if(s[i]==a[j]){
13                     f=1;cout<<b[j];
14                 }
15             if(f==0)cout<<s[i];
16         }
17         cout<<endl;
18     }
19     return 0;
20 }
D

E.Formula Racing回到顶部

题意

给一张n*m的图,W代表墙,s代表起跑线/目标线,.代表非跑道,x代表跑道

d辆车,给你起点方向和最大速度,在给一串操作序列

m代表前进,a代表速度+1再前进,b代表速度-1再前进,l代表左转再前进,r代表右转再前进

如果小车到了.,速度降为1

每辆车输出,如果到了s,输出crossing startline

如果小车没有撞墙输出终点方向速度

如果小车撞墙了就停止crashed

n,m<=1000,d<=7,len<=10000

题解

模拟每辆小车的操作,按照要求处理,复杂度O(sumlend)

坑1:注意n行m列,列代表y,行代表x,在判断的时候判断的是G[y][x]

坑2:如果小车最后撞墙,之前如果经过s也要输出crossing startline

PS:题意有点难理解

代码

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<vector>
 4 using namespace std;
 5 
 6 const int N=1005;
 7 
 8 char G[N][N];
 9 int dx[]={0,1,1,1,0,-1,-1,-1};
10 int dy[]={-1,-1,0,1,1,1,0,-1};
11 struct node{
12     int ux,uy,dir,sp,i;
13 };
14 int main(){
15     int t,n,m,q;
16     scanf("%d",&t);
17     for(int ca=1;ca<=t;ca++){
18         scanf("%d%d",&n,&m);
19         for(int i=0;i<n;i++)scanf("%s",G[i]);
20         scanf("%d",&q);
21         printf("Scenario #%d:
",ca);
22         while(q--){
23             int ux,uy,dir,spm,sp=0;char op[10005];
24             scanf("%d%d%d%d%s",&ux,&uy,&dir,&spm,op);
25             //printf("%d %d %d %d %s
",ux,uy,dir,spm,op);
26             vector<node>vec;
27             int len=strlen(op);
28             for(int i=0;i<len;i++){
29                 if(op[i]=='a'&&sp<spm)sp++;
30                 if(op[i]=='b'&&sp>0)sp--;
31                 if(op[i]=='l')dir=(dir+7)%8;
32                 if(op[i]=='r')dir=(dir+1)%8;
33                 int up=0;
34                 for(int j=1;j<=sp;j++){
35                     ux+=dx[dir],uy+=dy[dir];
36                     //printf("j=%d ux=%d uy=%d
",j,ux,uy);
37                     if(G[uy][ux]=='W'){
38                         printf("%d %d %d %d crashed
",ux,uy,dir,sp);
39                         goto e;
40                     }
41                     if(G[uy][ux]=='.')up=1;
42                     if(G[uy][ux]=='s')vec.push_back((node){ux,uy,dir,sp,i});
43                 }
44                 //printf("i=%d (%d,%d) dir=%d sp=%d
",i,ux,uy,dir,sp);
45                 if(up)sp=1;
46             }
47             printf("%d %d %d %d
",ux,uy,dir,sp);
48             e:;
49             for(int i=0;i<vec.size();i++)
50                 printf("crossing startline: %d %d %d %d %d
",vec[i].ux,vec[i].uy,vec[i].dir,vec[i].sp,vec[i].i);
51         }
52         printf("
");
53     }
54     return 0;
55 }
E

F.Helping Florida回到顶部

题意

n个候选人,m张选票,每轮选举淘汰票数最少的(可以有多个最少),对于选票来说如果这个候选人被淘汰,那么就推到下一个候选人

选票的结构是,候选人1,候选人2,候选人3......

到最后一轮或者候选者有>=(m+1)/2张票,对应的候选者获胜,可以有多个获胜

题解

模拟每轮被淘汰的候选人,注意处理选票的时候不要越界了,复杂度O(nm)

PS:唯一获胜XXX won,并列获胜it is a tie between XXX and XXX

PS:题意又是有点难理解

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 map<string,int>votes;
 5 vector<string>vec[105];
 6 int tail[105];
 7 int main(){
 8     ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 9     int n,m;string s,ss;
10     while(cin>>n>>m,n||m){
11         votes.clear();
12         for(int i=1;i<=m;i++)vec[i].clear(),tail[i]=0;
13         cin.get();
14         for(int i=1;i<=m;i++){
15             getline(cin,ss);
16             stringstream s(ss);
17             while(s>>ss)vec[i].push_back(ss);
18         }
19         map<string,int>dead;
20         for(int i=1;i<=m;i++)votes[vec[i][0]]++;
21         int t=0,MinVo,MaxVo;
22         while(1){
23             MinVo=1e9;MaxVo=0;
24             for(auto X:votes)MinVo=min(MinVo,X.second),MaxVo=max(MaxVo,X.second);
25             if(MaxVo>=(m+1)/2){
26                 t=1;
27                 break;
28             }
29             vector<string>del;
30             for(auto X:votes)if(MinVo==X.second)del.push_back(X.first);
31             if(del.size()==votes.size())break;
32             for(auto X:del){
33                 dead[X]=1,votes.erase(X);
34             }
35             int rup=0;
36             for(int i=1;i<=m;i++){
37                 int up=0;
38                 while(tail[i]<vec[i].size()&&dead.count(vec[i][tail[i]]))tail[i]++,up=1;
39                 if(tail[i]<vec[i].size()&&up)rup=1,votes[vec[i][tail[i]]]++;
40             }
41             if(rup==0)break;
42         }
43         vector<string>out;
44         if(t){
45             for(auto X:votes)if(X.second==MaxVo)out.push_back(X.first);
46         }
47         else{
48             for(auto X:votes)out.push_back(X.first);
49         }
50         if(out.size()==1)cout<<out[0]<<" won
";
51         else{
52             cout<<"it is a tie between "<<out[0];
53             for(int i=1;i<out.size();i++)
54                 cout<<" and "<<out[i];
55             cout<<'
';
56         }
57     }
58     return 0;
59 }
F

G.Double Shortest Paths回到顶部

题意

给一张有向图,边(u,v,a,b)第一次经过花费a,第二次经过花费a+b,问从1->n走两次的最小花费,n<=500,m<=2000

题解

最小费用最大流模板题,超级源点S(0)->1流量2花费0,n->超级汇点T(n+1)流量2花费0,其余(u,v,a,b),连两条,第一条u->v流量1花费a,第二条u->v流量1花费a+b,复杂度玄学(一般n<=500)

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int N=1e5+5;
  5 const int M=2e5+5;
  6 const int INF=0x3f3f3f3f;
  7 
  8 int FIR[N],FROM[M],TO[M],CAP[M],FLOW[M],COST[M],NEXT[M],tote;
  9 int pre[N],dist[N],q[400000];
 10 bool vis[N];
 11 int n,m,S,T;
 12 void init()
 13 {
 14     tote=0;
 15     memset(FIR,-1,sizeof(FIR));
 16 }
 17 void addEdge(int u,int v,int cap,int cost)
 18 {
 19     FROM[tote]=u;
 20     TO[tote]=v;
 21     CAP[tote]=cap;
 22     FLOW[tote]=0;
 23     COST[tote]=cost;
 24     NEXT[tote]=FIR[u];
 25     FIR[u]=tote++;
 26 
 27     FROM[tote]=v;
 28     TO[tote]=u;
 29     CAP[tote]=0;
 30     FLOW[tote]=0;
 31     COST[tote]=-cost;
 32     NEXT[tote]=FIR[v];
 33     FIR[v]=tote++;
 34 }
 35 bool SPFA(int s, int t)//寻找花销最少的路径
 36 {
 37     //跑一遍SPFA 找s——t的最少花销路径 且该路径上每一条边不能满流
 38     //若存在 说明可以继续增广,反之不能
 39     memset(dist,INF,sizeof(dist));
 40     memset(vis,false,sizeof(vis));
 41     memset(pre,-1,sizeof(pre));
 42     dist[s] = 0;vis[s]=true;q[1]=s;
 43     int head=0,tail=1;
 44     while(head!=tail)
 45     {
 46         int u=q[++head];vis[u]=false;
 47         for(int v=FIR[u];v!=-1;v=NEXT[v])
 48         {
 49             if(dist[TO[v]]>dist[u]+COST[v]&&CAP[v]>FLOW[v])//可以松弛 且 没有满流
 50             {
 51                 dist[TO[v]]=dist[u]+COST[v];
 52                 pre[TO[v]]=v;//记录前驱边 的编号
 53                 if(!vis[TO[v]])
 54                 {
 55                     vis[TO[v]] = true;
 56                     q[++tail]=TO[v];
 57                 }
 58             }
 59         }
 60     }
 61     return pre[t]!=-1;//可达返回true
 62 }
 63 void MCMF(int s, int t, int &cost, int &flow)
 64 {
 65     flow=0;//总流量
 66     cost=0;//总费用
 67     while(SPFA(s,t))//每次寻找花销最小的路径
 68     {
 69         int Min = INF;
 70         //通过反向弧 在源点到汇点的最少花费路径 找最小增广流
 71         for(int v=pre[t];v!=-1;v=pre[TO[v^1]])
 72             Min = min(Min, CAP[v]-FLOW[v]);
 73         //增广
 74         for(int v=pre[t];v!=-1;v=pre[TO[v^1]])
 75         {
 76             FLOW[v]+=Min;
 77             FLOW[v^1]-=Min;
 78             cost+=COST[v]*Min;//增广流的花销
 79         }
 80         flow+=Min;//总流量累加
 81     }
 82 }
 83 int main(){
 84     int ca=0;
 85     while(scanf("%d%d",&n,&m)!=EOF){
 86         init();
 87         for(int i=0,u,v,d,a;i<m;i++){
 88             scanf("%d%d%d%d",&u,&v,&d,&a);
 89             addEdge(u,v,1,d);
 90             addEdge(u,v,1,d+a);
 91         }
 92         S=0,T=n+1;
 93         addEdge(S,1,2,0);
 94         addEdge(n,T,2,0);
 95         int cost,flow;
 96         MCMF(S,T,cost,flow);
 97         printf("Case %d: %d
",++ca,cost);//最小费用 最大流
 98     }
 99     return 0;
100 }
G

H.Discrepancies in the Voters List回到顶部

题意

给n1,n2,n3个数,问出现>=2的数,n1,n2,n3<=50000

题解

map哈希求次数>=2,复杂度O(sumnlog(sumn))

PS:题意也没说会不会出现相同的,没有相同的话上面这么做

PS:如果有相同的话,处理map<int,int>f[3]判断是否都有

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 map<int,int>ma;
 5 int main(){
 6     int n1,n2,n3,x;
 7     scanf("%d%d%d",&n1,&n2,&n3);
 8     for(int i=1;i<=n1;i++)scanf("%d",&x),ma[x]++;
 9     for(int i=1;i<=n2;i++)scanf("%d",&x),ma[x]++;
10     for(int i=1;i<=n3;i++)scanf("%d",&x),ma[x]++;
11     int cnt=0;
12     for(auto X:ma)if(X.second>=2)cnt++;
13     printf("%d
",cnt);
14     for(auto X:ma)if(X.second>=2)printf("%d
",X.first);
15     return 0;
16 }
H

I.Optimal Programs回到顶部

题意

求一个操作序列,ADD,SUB,MUL,DIV分别是从栈顶取出两个再做对应操作,DUP是复制栈顶元素

f(x)=y代表栈初始值x,经过操作序列操作后,得到最后的值为y,要求对于每个x[i]都可以推出y[i]

n<=10,答案操作序列<=10

题解

最暴力的做法是5^10*10*10肯定不行,需要优化,这里优化的东西挺多的

优化1:如果当前序列存在除0,栈顶弹不出2个,这个序列就不用搜索下去了

优化2:如果最后栈的大小不为1,f(x[i])!=y[i]可以快速判断非法,可以继续搜索

优化3:如果所有x[i]=y[i]那么直接输出Empty sequence

优化4:初始只有一个x[i],那么第一次操作一定为DUP

复杂度O(<<5^9*10*10)

PS:又是一道特别难理解的题,淦

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 //0 ADD
  5 //1 DUP
  6 //2 DIV
  7 //3 MUL
  8 //4 SUB
  9 int f,path[10],x[10],y[10],n;
 10 char out[5][5]={"ADD","DIV","DUP","MUL","SUB"};
 11 struct node{
 12     int path[10];
 13     int p;
 14 };
 15 //check=0序列不合法,1序列合法答案不合法,2序列合法答案合法
 16 int check(node v){
 17     //for(int i=0;i<=v.p;i++)printf("%d ",v.path[i]);
 18     //puts("");
 19     for(int i=0;i<n;i++){
 20         stack<int>st;
 21         st.push(x[i]);
 22         int a,b;
 23         for(int j=0;j<=v.p;j++){
 24             if(v.path[j]==0){
 25                 if(!st.empty())a=st.top(),st.pop();
 26                 else return 0;
 27                 if(!st.empty())b=st.top(),st.pop();
 28                 else return 0;
 29                 if(a+b<-30000||a+b>30000)return 0;
 30                 else st.push(a+b);
 31             }else if(v.path[j]==1){
 32                 if(!st.empty())a=st.top(),st.pop();
 33                 else return 0;
 34                 if(!st.empty())b=st.top(),st.pop();
 35                 else return 0;
 36                 if(a==0)return 0;
 37                 else if(b/a<-30000||b/a>30000)return 0;
 38                 else st.push(b/a);
 39             }else if(v.path[j]==2){
 40                 if(!st.empty())a=st.top();
 41                 else return 0;
 42                 st.push(a);
 43             }else if(v.path[j]==3){
 44                 if(!st.empty())a=st.top(),st.pop();
 45                 else return 0;
 46                 if(!st.empty())b=st.top(),st.pop();
 47                 else return 0;
 48                 if(a*b<-30000||a*b>30000)return 0;
 49                 else st.push(a*b);
 50             }else if(v.path[j]==4){
 51                 if(!st.empty())a=st.top(),st.pop();
 52                 else return 0;
 53                 if(!st.empty())b=st.top(),st.pop();
 54                 else return 0;
 55                 if(b-a<-30000||b-a>30000)return 0;
 56                 else st.push(b-a);
 57             }
 58         }
 59         if(st.size()!=1)return 1;
 60         else if(st.top()!=y[i])return 1;
 61     }
 62     return 2;
 63 }
 64 void bfs(){
 65     queue<node>q;
 66     node s;
 67     s.path[0]=2;s.p=0;
 68     q.push(s);
 69     while(!q.empty()){
 70         node u=q.front();q.pop();
 71         for(int i=0;i<=4;i++){
 72             if(u.p+1<=9){
 73                 node v=u;
 74                 v.path[u.p+1]=i;v.p++;
 75                 int oo=check(v);
 76                 if(oo==1)q.push(v);
 77                 else if(oo==2){
 78                     for(int j=0;j<=v.p;j++)path[j]=v.path[j];
 79                     f=v.p;return;
 80                 }    
 81             }
 82         }
 83     }
 84 }
 85 int main(){
 86     int ca=1;
 87     while(scanf("%d",&n)!=EOF,n){
 88         for(int i=0;i<n;i++)scanf("%d",&x[i]);
 89         for(int i=0;i<n;i++)scanf("%d",&y[i]);
 90         int same=1;
 91         for(int i=0;i<n;i++)if(x[i]!=y[i])same=0;
 92         //5^10=9e6
 93         printf("Program %d
",ca++);
 94         if(same){
 95             printf("Empty sequence

");
 96             continue;
 97         }
 98         f=-1;
 99         bfs();
100         if(f>-1){
101             printf("%s",out[path[0]]);
102             for(int i=1;i<=f;i++)
103                 printf(" %s",out[path[i]]);
104             printf("
");
105         }
106         else printf("Impossible
");
107         puts("");
108     }
109     return 0;
110 }
I

J.Bovine Bridge Battle回到顶部

题意

n个点,问多少个4元组两两对称,n<=1000

题解

求出每两个点的中点,统计次数,为了防止出现小数,可以先*2

然后遍历所有中点,可以发现就是C(n,2),复杂度O(2n^2logn)

PS:可以把pair<int,int>hash成一个long,然后存在unordered中可以少个log,复杂度O(n^2)

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define LL long long
 5 
 6 const int N=1005;
 7 
 8 int x[N],y[N];
 9 map<pair<int,int>,int>ma;
10 
11 int main(){
12     int n;
13     scanf("%d",&n);
14     for(int i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]);
15     for(int i=1;i<=n;i++)x[i]<<=1,y[i]<<=1;
16     for(int i=1;i<=n;i++)for(int j=1;j<i;j++){
17         int x1=(x[i]+x[j])/2;
18         int y1=(y[i]+y[j])/2;
19         ma[{x1,y1}]++;
20     }
21     LL ans=0;
22     for(auto X:ma)ans+=(1LL*X.second*(X.second-1))/2;
23     printf("%lld",ans);
24     return 0;
25 }
J
原文地址:https://www.cnblogs.com/taozi1115402474/p/12818066.html