赞
踩
水平有限错误难免。
时间限制:1 s
题目描述:
求整数序列A 中位置L 到R中间一共有多少个7,(每一个位上的7和能被7整除的次数)
第一行是T(T<=50)
然后是T行 L R (L<R<1 e 5)
输出7的个数
2
1 10
47 50
2
3
第二组数据解释 47 中含有一个7 49含有2个7 所以输出3
暴力搜索
#include<bits/stdc++.h> using namespace std; int t; int l,r,ans; int slove(int x){ int ans1=0,tmp=x; while(x!=0){ int k=x%10; if(k==7)ans1++; x/=10; } while(tmp%7==0){ ans1++; tmp/=7; } return ans1; } int main(){ scanf("%d",&t); while(t--){ ans=0; scanf("%d%d",&l,&r); for(int i=l;i<=r;i++){ ans+=slove(i); } printf("%d\n",ans); } return 0; }
时间限制:3 s
题目描述:
在程序员编写程序的时候,通常会引用其他文件,而引用的文件也会引用其它的头文件。但是出现循环引用的现象编译时便会报错。例如A引用了B,B引用了C,C引用了A,那么就产生了循环引用(Circular reference)。考虑另外一个情况,A引用了B和C,B引用D,C引用D,虽然D被引用了两次,但是没有出现循环引用 。
第一行是一个整数T,代表测试数据的组数。每组数据中第一行是一个整数n,代表有多少个引用关系。接下来n行每行有2个字符串a,b,用空格分隔,代表a引用了b。其中T<=50, n<=10^5,每个字符串的长度不超过100。
共T行。若不会产生编译错误则输出Passed,否则输出Failed。
2
8
client.cpp client.h
client.h server.h
server.cpp server.h
server.h common.h
client.h common.h
common.cpp common.h
common.h gtest.h
common.h glog.h
4
work.cpp client.cpp
client.cpp server.cpp
server.cpp adhoc.cpp
adhoc.cpp work.cpp
Passed
Failed
如果能够拓扑排序说明不会产生编译错误,如果不能拓扑排序说明出现了循环引用。
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; struct edge{ int next,to; }; edge e[maxn]; int t,n,cnt,ind[maxn],head[maxn]; string a,b; map<string,int> mp; void add_edge(int u,int v){ cnt++; e[cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; } bool topsort(){ int num=0; queue<int>q; for(int i=1;i<=n;i++){ if(ind[i]==0){ q.push(i); } } while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; ind[v]--; if(ind[v]==0){ q.push(v); } } num++; } if(num==n)return true; else return false; } int main(){ scanf("%d",&t); while(t--){ int tot=0,u,v; cnt=0; memset(head,0,sizeof(head)); memset(ind,0,sizeof(ind)); memset(e,0,sizeof(struct edge)*maxn); mp.clear(); scanf("%d",&n); for(int i=1;i<=n;i++){ cin>>a>>b; if(mp.find(a)==mp.end()){ mp.insert(pair<string,int>(a,++tot)); u=tot; } else u=mp[a]; if(mp.find(b)==mp.end()){ mp.insert(pair<string,int>(b,++tot)); v=tot; } else v=mp[b]; add_edge(v,u); ind[u]++; } if(topsort())printf("Passed\n"); else printf("Failed\n"); } return 0; }
时间限制:3 s
题目描述:
同学们在做早操时,应该按照身高从低到高排好队。但是总是有人不好好排队,老师在审查时会对没有排好的队伍扣除一定的分数。扣的分数被定义为,找到三个人Ai,Aj,Ak,其中i<j<k,分数为max(0,(Ai-Aj))+max(0,(Aj-Ak))。找到一组i,j,k使这个分数最大即是扣除的分数。
第一行是一个整数T,代表测试数据的组数。每组数据中第一行是一个整数n,代表有一共有多少个人。第二行共有n个整数,代表n个人的身高。其中1<=T<=50,3<=n<=10^6 每个数的大小不超过1000。
共T行。扣除的分数。
2
4
150 160 170 180
4
160 150 170 180
0
10
该题是寻找一个i,j,k,满足(i<j<k)但i,j,k并不一定连续,如果我们枚举中间数j,从2到n-2,对于每一次枚举,我们都需要对i,k分别枚举,时间复杂度为O(n2),肯定不能通过。我们其实在枚举过程中重复了很多计算,对于每一个j,我们的目的是寻找i<j的a[i]最大值,k>j的a[k]最小值。
我们可以预先处理,用两个数组mx[i],mn[i],mx[i]表示i之前a[i]的最大值(不包括a[i]),mn[i]表示以i之后a[i]的最小值。然后我们直接枚举max(mx [i]-a[i],0)+ max(a[i]-mn[i]),时间复杂度为O(n);
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+5; int mx[maxn],mn[maxn]; int t,n; int a[maxn]; int main(){ scanf("%d",&t); while(t--){ int ans=0; memset(mx,0,sizeof(mx)); memset(mn,0,sizeof(mn)); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } mx[1]=a[1],mn[n]=a[n]; for(int i=2;i<=n-1;i++){ mx[i]=max(mx[i-1],a[i-1]); } for(int i=n-1;i>=2;i--){ mn[i]=min(mn[i+1],a[i+1]); } for(int i=2;i<=n-1;i++){ ans=max(max(mx[i]-a[i],0)+max(a[i]-mn[i],0),ans); } printf("%d\n",ans); } return 0; }
时间限制:3 s
题目描述:
小七初始有n个数的样本集。现在又新加了m个数,他想知道这m个数是否已经在这n个数之中了。但是他判断是否有重复的方式和常人有些不同。对于样本集内的任意一个数x,他先将x二进制的第2, 5, 7, 10, 13, 14, 17, 18位取反,生成新的8个数。例如x是7(00111),那么第一个数就是5(00101),第二个数是23(10111)…依次类推。然后将他表格上这8个数的位置全部变为1(初始整个表格全部为0)。判断重复时,若一个数x产生的8个数,在表格内全部为1,就认为这个数x和样本集内的数有重复,否则认为没有重复
输入T,代表T组数据。每组数据初始输入n, m。代表n个样本以及m个需要判断的数。接下来两行,第一行是n个样本,第二行m个需要判断的数,样本在前。对于这m个数,每个数输出yes 或者 no。m组数据相互独立,即这m个数都不会新加入到样本集内。其中T<=50 ,n,m<1e5 。
输出一行,共m个字符串,重复输出yes,否则输出no,空格隔开
1
2 2
2 1
3 2
no yes
按位取异或加入集合s,再判重。
#include<bits/stdc++.h> using namespace std; int a[8]={2,5,7,10,13,14,17,18}; int t,n,m; set<int>s; int main(){ scanf("%d",&t); while(t--){ s.clear(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ int x; scanf("%d",&x); for(int j=0;j<=7;j++){ int y=x^(1<<(a[j]-1)); s.insert(y); } } for(int i=1;i<=m;i++){ int x; scanf("%d",&x); int flag=1; for(int j=0;j<=7;j++){ int y=x^(1<<(a[j]-1)); if(s.find(y)==s.end()){ flag=0; break; } } if(flag){ printf("yes "); } else printf("no "); } } return 0; }
时间限制:3 s
题目描述:
给定n个整数,对其进行m次查询。每次查询是一个范围l到r,求出l到r的最长上升连续子串。上升连续子串的定义为一个连续的子串且严格递增。
第一行是一个整数T,代表测试数据的组数。每组数据中第一行是一个整数n,m,代表有一共有n个人,m个查询。第二行共有n个整数,接下来m行是m次查询,每行两个整数l,r。
共T行,每行m个整数,代表最长上升连续字串。其中T<=50,n,m<1e5,每个数的大小不超过1e9。
1
4 2
3 2 4 5
1 3
1 4
2
3
最长连续上升子串,很容易想到动态规划求解。但本题数据量很大,用动态规划无论是时间还是空间可能都过不去。区间最大值,可以用线段树求解,而且不用更新操作。
线段树维护三个值,lv是区间左端点开始的最长上升连续值,rv是以区间右端点结束的最长上升连续值,mv是该区间的最长上升连续值,pushup时分类讨论,当a[mid]<a[mid+1]时,我们可以知道该区间中间两个点是递增的。这是线段树的区间合并操作,如果你有兴趣的话,可以试一试
hdu-3308
本题就是这题的简化版。
#include<bits/stdc++.h> using namespace std; const int maxn=100005; using namespace std; struct node{ int l,r; int lv,rv,mv; }; node tree[maxn*4+5]; int t,n,m,a[maxn]; void pushup(int i,int l,int r){ int mid=(l+r)>>1; if(tree[i<<1].lv==mid-l+1&&a[mid]<a[mid+1]){ tree[i].lv=tree[i<<1].lv+tree[i<<1|1].lv; } else tree[i].lv=tree[i<<1].lv; if(tree[i<<1|1].rv==r-mid&&a[mid]<a[mid+1]){ tree[i].rv=tree[i<<1].rv+tree[i<<1|1].rv; } else tree[i].rv=tree[i<<1|1].rv; tree[i].mv=max(tree[i<<1].mv,tree[i<<1|1].mv); if(a[mid]<a[mid+1]){ tree[i].mv=max(tree[i].mv,tree[i<<1].rv+tree[i<<1|1].lv); } } void build(int i,int l,int r){ tree[i].l=l; tree[i].r=r; if(l==r){ tree[i].lv=tree[i].rv=tree[i].mv=1; return ; } int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); pushup(i,l,r); } int query(int i,int x,int y){ if(tree[i].l>=x&&tree[i].r<=y){ return tree[i].mv; } int mid=(tree[i].l+tree[i].r)>>1; int mx=0; if(x<=mid){ mx=max(mx,query(i<<1,x,y)); } if(y>mid){ mx=max(mx,query(i<<1|1,x,y)); } if(a[mid]<a[mid+1]){ mx=max(mx,min(tree[i<<1].rv,mid-x+1)+min(tree[i<<1|1].lv,y-mid)); } return mx; } int main(){ scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); memset(a,0,sizeof(a)); memset(tree,0,sizeof(struct node)*4*maxn); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } build(1,1,n); while(m--){ int x,y; scanf("%d%d",&x,&y); printf("%d\n",query(1,x,y)); } } return 0; }
时间:3 s
题目描述: 在一个群岛上,有一个富可敌国的大富翁。他打算在这个群岛上建造一个最大城堡,也就是群岛上最大的岛屿。
第一行是一个整数T,代表测试数据的组数。每组数据中第一行是两个整数n,m,代表地图的大小。接下来n行每行共m个整数。0代表海洋,1代表陆地。其中T<=50,n,m<=200 。
共T行,最大的面积。
1
5 5
0 1 1 0 0
1 1 0 0 0
0 0 1 1 0
0 1 1 1 1
0 0 1 1 0
8
dfs或bfs求最大连通块
#include<bits/stdc++.h> using namespace std; const int maxn=205; int t,n,m,ans,area; int g[maxn][maxn]; bool vis[maxn][maxn]; void dfs(int x,int y){ if(x<1||x>n||y<1||y>m)return ; if(vis[x][y]||!g[x][y])return ; vis[x][y]=true; area++; dfs(x-1,y); dfs(x+1,y); dfs(x,y-1); dfs(x,y+1); } int main(){ scanf("%d",&t); while(t--){ memset(vis,false,sizeof(vis)); memset(g,0,sizeof(g)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&g[i][j]); } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(!vis[i][j]&&g[i][j]){ area=0; dfs(i,j); ans=max(area,ans); } } } printf("%d\n",ans); } return 0; }
时间:5s
题目描述:
《炉石传说》是一款考验技(shen)术(chou)的电子游戏,即使你没有玩过这个游戏也没有关系。《炉石传说》里有一张萨满卡牌叫做连环爆裂,它的效果是等概率的造成3-6点伤害。而游戏获胜的条件是将对方英雄的血量全部打掉。例如对方英雄还有5点生命值,你有1张连环爆裂,那么你获胜的概率为0.5。在本题中你无需考虑法力值消耗。
第一行是一个整数T,代表测试数据的组数。接下来的T行每行有2个整数n,h,n代表你一共可以释放的连环爆裂的个数,h代表敌方英雄的血量。其中T<=50,n<=5000,h<=30000。
共T行,每行是一个小数,保留到小数点后6位。
1
1 5
0.500000
由于是等概率造成伤害,每次打出卡牌造成的伤害p(3)=1/4,p(4)=1/4,p(5)=(1/4),p(6)=1/4;dp[ i ] [ j]表示i张牌时血量为j的答案。对于每次一的(n,h)都等于(n-1,h-3)+(n-1,h-4)+(n-1,h-5)+(n-1,h-6),递归求解可行,但n达到5000,h达到30000,所以可以使用递推。递推一定要处理好边界。
时间复杂度小于O(t+4 * 3000 * 50000)。
#include<bits/stdc++.h> using namespace std; const int maxn=5000; const int maxh=30000; int t,n,h; double dp[maxn+5][maxh+5]; int main(){ scanf("%d",&t); for(int i=1;i<=maxn;i++){ for(int j=0;j<=3*i&&j<=maxh;j++){ dp[i][j]=1.000000; } } dp[1][4]=0.750000,dp[1][5]=0.5000000,dp[1][6]=0.25000000; for(int i=2;i<=maxn;i++){ for(int j=3*i+1;j<=maxh;j++){ for(int k=3;k<=6;k++){ if(j-k>=0)dp[i][j]+=dp[i-1][j-k]*0.25; } } } while(t--){ scanf("%d%d",&n,&h); printf("%.6lf\n",dp[n][h]); } return 0; }
时间:5 s
题目描述:
在一个运输公司中有很多型号完全一样的卡车,每个卡车都可以装载重量为w的货物。有若干个需要运输的货物an,每个货物ai都有一个质量mi。这个运输公司对于这些货物的装载方式策略是,每一次尽可能装更多质量的货物,在有多种可以装载最多质量的货物的方式时,会选择货物下标字典序最小的一组。例如货物的质量为4 3 2 1,卡车能够装载的质量为5时,第一次会选择4 1而不是2 3 。
第一行是一个整数T,代表测试数据的组数。每组样例中,第一行有两个整数n,w,代表有n个货物,每个卡车可以装载质量w的货物。接下来一行有n个数字,代表每个货物的质量。其中T≤20,n,w≤1000。每个货物的质量不会超过w。
共T行,输出所需要的卡车数量。
2
4 4
3 3 3 3
4 4
2 2 2 2
4
2
多重01背包,价值与容量相等,每次计算以后将字典序最小的物品进行标记。
这样时间复杂度最差有O(n3),可能还需要加bitset优化背包。
#include<bits/stdc++.h> using namespace std; const int maxn=1005; const int inf =0x3f3f3f3f; int n,w,t; int dp[maxn][maxn],a[maxn],ans,num; bool vis[maxn]; int main(){ scanf("%d",&t); while(t--){ ans=0,num=0; memset(vis,true,sizeof(vis)); scanf("%d%d",&n,&w); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } while(num<n){ ans++; memset(dp,0,sizeof(dp)); for(int i=n;i>=1;i--){ for(int j=0;j<=w;j++){ dp[i][j]=dp[i+1][j]; if(j>=a[i]&&vis[i]){ dp[i][j]=max(dp[i][j],dp[i+1][j-a[i]]+a[i]); } } } int cur_v=w; for(int i=1;i<=n;i++){ if(i==n&&cur_v>=a[i]&&vis[i]){ vis[i]=false; num++; break; } if(cur_v<=0)break; if(cur_v-a[i]>=0&&dp[i][cur_v]==dp[i+1][cur_v-a[i]]+a[i]&&vis[i]){ vis[i]=false; num++; cur_v=cur_v-a[i]; } } } printf("%d\n",ans); } return 0; }
时间:5 s
题目描述:
有一个01的大矩阵,找到一个最大由1围城的矩形框的面积。
第一行是一个整数T,代表测试数据的组数。每组样例中,第一行有两个整数n,m,代表有大矩阵的大小,接下来是一个由01组成的大矩阵。其中T<=10,n,m<=200。
最大由1围成的矩形框的面积。
1
5 5
0 1 0 1 0
1 1 1 1 0
1 1 0 1 1
1 1 1 1 1
0 1 1 1 1
12
枚举矩形框的上下界,在从左往右扫描。我们可以用数组sum[i] [j].x存储第i行j列的数前面连续多少1,
sum[i] [j].y上面连续多少个1,计算时直接使用。
#include<bits/stdc++.h> using namespace std; const int maxn=205; struct node{ int x,y; }; int t; int a[maxn][maxn]; node sum[maxn][maxn]; int n,m,ans; int main(){ scanf("%d",&t); while(t--){ ans=0; scanf("%d%d",&n,&m); memset(sum,0,sizeof(struct node)); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); if(a[i][j]){ sum[i][j].x=sum[i][j-1].x+1; sum[i][j].y=sum[i-1][j].y+1; } } } for(int i=1;i<=n;i++){ for(int j=i;j<=n;j++){ for(int k=1;k<=m;k++){ int h,w; h=j-i+1; w=min(sum[i][k].x,sum[j][k].x); if(sum[j][k].y>=h)for(int l=w;l>=1;l--){ if(sum[j][k-l+1].y>=h){ int area=l*h; ans=max(area,ans); break; } } } } } printf("%d\n",ans); } return 0; }
时间:3 s
题目描述: 有n个整数,分成m段。使每一段的和的最小值尽可能的大。
第一行是一个整数T,代表测试数据的组数。每组样例中,第一行有两个整数n,m,接下来一行是n个整数。其中T<=50,n,m<1e5 。
尽可能的大的每一段的和的最小值。
1
5 3
4 5 4 5 1
4
最小化最大值,二分+贪心。
我们check时对于,sum如果大于等于k立即划分为一段,num++,如果num大于等于m的,说明该k值一定满足。
#include<bits/stdc++.h> using namespace std; int n,m; int a[100005]; int t,r,l,ans; bool check(int k){ int sum=0,num=0; for(int i=1;i<=n;i++){ if(a[i]+sum>=k){ num++; sum=0; }else{ sum+=a[i]; } } if(num>=m)return true; else return false; } int main(){ scanf("%d",&t); while(t--){ r=0,l=0x3f3f3f3f; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); r+=a[i]; l=min(l,a[i]); } while(l<=r){ int mid=(l+r)/2; if(check(mid))ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); } return 0; }
时间:3 s
题目描述:
Alice和Bob进行一款质数游戏,Alice先说一个质数或者1,Bob再加上一个质数或者1。不能超过目标数字,谁先喊道目标数字就获胜。Alice和Bob都足够聪明,都会采用最优策略。
第一行是一个整数T,代表测试数据的组数。每组样例中,第一行有一个整数n,代表目标数字。
T<=20,n<1e18
共T行,输出Alice win或者Bob win。
2
4
6
Bob win
Alice win
首先,我们需要知道一个定理:一切大于2的质数,一定是形如4n+1或4n-1的数。
由于我们每次给的数可以是1,2,3+(大于2的)质数。那么无论谁先讲,后手的一定可以加成4n。所以说,只要给的数能够被4整除,Bob必胜。反之,Alice必胜。当然你可以找规律,也能写出来。
#include<bits/stdc++.h> using namespace std; typedef long long ll; int t; ll n; int main(){ scanf("%d",&t); while(t--){ cin>>n; if(n%4==0){ printf("Bob win\n"); } else printf("Alice win\n"); } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。