vjudge个人赛 复习1
A - 大鱼吃小鱼(栈)
有N条鱼每条鱼的位置及大小均不同,他们沿着X轴游动,有的向左,有的向右。游动的速度是一样的,两条鱼相遇大鱼会吃掉小鱼。从左到右给出每条鱼的大小和游动的方向(0表示向左,1表示向右)。问足够长的时间之后,能剩下多少条鱼?Input第1行:1个数N,表示鱼的数量(1 <= N <= 100000)。
第2 - N + 1行:每行两个数A[i], B[i],中间用空格分隔,分别表示鱼的大小及游动的方向(1 <= A[i] <= 10^9,B[i] = 0 或 1,0表示向左,1表示向右)。Output输出1个数,表示最终剩下的鱼的数量。Sample Input
5
4 0
3 1
2 0
1 0
5 0
Sample Output
2
/*
对于第i条鱼,如果方向朝右进栈。向左的话,跟栈每一个元素j比较,如果i>j 那么j死,继续访问j前面的元素(知道栈空或者死),,, 否则i死, 继续遍历i+1以及后面的元素
*/
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 100010
int st[maxn],top,n,cnt;
int main(){
scanf("%d",&n);cnt=n;
int x,y;
for(int i=;i<=n;i++){
scanf("%d%d",&x,&y);
if(y==)st[++top]=x;
else{
while(top){
if(x>st[top]){top--;cnt--;}
else {cnt--;break;}
}
}
}
cout<<cnt;
}
AC代码 用栈维护
B - 线段的重叠(贪心)
Input第1行:线段的数量N(2 <= N <= 50000)。
第2 - N + 1行:每行2个数,线段的起点和终点。(0 <= s , e <= 10^9)Output输出最长重复区间的长度。Sample Input
5
1 5
2 4
2 8
3 7
7 9
Sample Output
4
#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 50010
using namespace std;
int n;
struct node{
int l,r;
bool operator < (const node a)const{
return l<a.l;
}
}e[maxn];
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d%d",&e[i].l,&e[i].r);
sort(e+,e+n+);
int ans=;
for(int i=;i<=n;i++)
for(int j=i+;j<=n;j++){
if(e[i].r>e[j].r)
ans=max(ans,e[j].r-e[j].l);
else
ans=max(ans,e[i].r-e[j].l);
}
cout<<ans;
}
80分 n^2暴力
/*
贪心,按照线段左端点升序排序,
左端点相等,右端点降序排序
*/
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAX=;
struct Node{
int b,e;
};
Node a[MAX];
int cmp(Node p1,Node p2){
if(p1.b<p2.b) return ;
else if(p1.b==p2.b&&p1.e>p2.e) return ;
return ;
}
int main()
{
int n;
while(cin>>n){
for(int i=;i<n;i++){
cin>>a[i].b>>a[i].e;
}
sort(a,a+n,cmp);
int res=;
Node s=a[];
for(int i=;i<n;i++){
if(a[i].e<=s.e){//线段i在线段i-1内
res=max(res,a[i].e-a[i].b);
}
else if(a[i].b<=s.e&&a[i].e>s.e){
res=max(res,s.e-a[i].b);
s=a[i];//选择最靠后的线段
}
else s=a[i];
}
cout<<res<<endl;
}
return ;
}
100分 贪心
C - 3个数和为0(暴力枚举)
给出一个长度为N的无序数组,数组中的元素为整数,有正有负包括0,并互不相等。从中找出所有和 = 0的3个数的组合。如果没有这样的组合,输出No Solution。如果有多个,按照3个数中最小的数从小到大排序,如果最小的数相等则按照第二小的数排序。
Input第1行,1个数N,N为数组的长度(0 <= N <= 1000)
第2 - N + 1行:A[i](-10^9 <= A[i] <= 10^9)Output如果没有符合条件的组合,输出No Solution。
如果有多个,按照3个数中最小的数从小到大排序,如果最小的数相等则继续按照第二小的数排序。每行3个数,中间用空格分隔,并且这3个数按照从小到大的顺序排列。Sample Input
7
-3
-2
-1
0
1
2
3
Sample Output
-3 0 3
-3 1 2
-2 -1 3
-2 0 2
-1 0 1
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 1010
int n,a[maxn],b[];
void dfs(int pos,int cnt,int sum){
if(cnt==){
if(sum==){
for(int i=;i<=;i++)printf("%d ",b[i]);
printf("\n");
}
return;
}
if(pos>n)return;
for(int i=pos;i<=n;i++){
b[cnt]=a[i];
dfs(i+,cnt+,sum+a[i]);
}
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
sort(a+,a+n+);
dfs(,,);//到底几个数了,已经确定了几个数-1,目前的和
}
60分 暴力
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 1010
int n,a[maxn];
bool flag;
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
sort(a+,a+n+);
for(int i=;i<=n;i++)
for(int j=i+;j<=n;j++)
for(int k=j+;k<=n;k++)
if(a[i]+a[j]+a[k]==){
flag=;
printf("%d %d %d\n",a[i],a[j],a[k]);
}
if(!flag)printf("No Solution");
return ;
}
100分 枚举n^3
D - 复杂度n^2log(n^2)(折半枚举)
给出N个整数,你来判断一下是否能够选出4个数,他们的和为0,可以则输出"Yes",否则输出"No"。Input第1行,1个数N,N为数组的长度(4 <= N <= 1000)
第2 - N + 1行:A[i](-10^9 <= A[i] <= 10^9)Output如果可以选出4个数,使得他们的和为0,则输出"Yes",否则输出"No"。Sample Input
5
-1
1
-5
2
4
Sample Output
Yes
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
int n,a[];
map<int,bool>f;
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
sort(a+,a+n+);
int mid=n/;
for(int i=;i<=mid;i++){
for(int j=i+;j<=mid;j++){
int x=a[i]+a[j];
f[x]=;
}
}
for(int i=mid+;i<=n;i++){
for(int j=i+;j<=n;j++){
int x=-(a[i]+a[j]);
if(f[x]){
printf("Yes");
return ;
}
}
}
printf("No");
return ;
}
排序+暴力+二分1
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[];
int main(){
int n;
scanf("%d",&n);
for(int i=;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
for(int i=;i<n;i++)
for(int j=i+;j<n;j++){
int k,m,sum;
k=j+;
m=n-;
while(k<m) {
sum=a[i]+a[j]+a[k]+a[m];
if(sum<)k++;
else if(sum>)m--;
else{
k++;m--;
printf("Yes\n");
return ;
}
}
}
printf("No\n");
return ;
}
排序+暴力+二分2
/*
还有个很好的思路,先把数组中任意两个数存起来,再从小到大排序,类似二分的思想从两头开始查找,是否满足sum1+sum2==0 并且两个坐标不重叠,每个点只选一次
*/
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
int a[];
struct node{
int x, y;
int sum;
}P[*]; int cmp(node a, node b) {
return a.sum < b.sum;
}
int main(){
int n;
scanf("%d", &n);
for(int i=;i<n;i++)scanf("%d",&a[i]);
int k=;
for(int i=;i<n;i++)
for(int j=i+;j<n;j++) {
P[k].x=a[i];
P[k].y=a[j];
P[k++].sum=a[i]+a[j];
}
sort(P,P+k,cmp);
int l=,r=k-;
int flag=;
while(l<r){
if (P[l].sum+P[r].sum==&&P[l].x!=P[r].x&&P[l].y!=P[r].y&&P[l].x!=P[r].y&&P[l].y!=P[r].x){
flag = ;
break;
}
else if(P[l].sum+P[r].sum<)l++;
else r--;
}
if (flag)printf("Yes\n");
else printf("No\n");
return ;
}
一种新做法
E - 和为K的组合(搜索)
给出N个正整数组成的数组A,求能否从中选出若干个,使他们的和为K。如果可以,输出:"Yes",否则输出"No"。Input第1行:2个数N, K, N为数组的长度, K为需要判断的和(2 <= N <= 20,1 <= K <= 10^9)
第2 - N + 1行:每行1个数,对应数组的元素A[i] (1 <= A[i] <= 10^6)Output如果可以,输出:"Yes",否则输出"No"。Sample Input
5 13
2
4
6
8
10
Sample Output
No
#include<iostream>
#include<cstdio>
using namespace std;
int n,k,a[];
bool flag;
void dfs(int pos,int sum){
if(sum==k){
flag=;
return;
}
if(pos>=n)return;
if(flag)return;
for(int i=pos+;i<=n;i++)
dfs(i,sum+a[i]);
}
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
if(k==){
printf("Yes");
return ;
}
dfs(,);
if(flag){
printf("Yes");
return ;
}
else printf("No");
return ;
}
AC代码 直接深搜
F - 数组中和等于K的数对(枚举+二分)
Input第1行:用空格隔开的2个数,K N,N为A数组的长度。(2 <= N <= 50000,-10^9 <= K <= 10^9)
第2 - N + 1行:A数组的N个元素。(-10^9 <= A[i] <= 10^9)Output第1 - M行:每行2个数,要求较小的数在前面,并且这M个数对按照较小的数升序排列。
如果不存在任何一组解则输出:No Solution。Sample Input
8 9
-1
6
5
3
4
2
9
0
8
Sample Output
-1 9
0 8
2 6
3 5
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int k,n,a[];
bool flag;
int main(){
//freopen("Cola.txt","r",stdin);
scanf("%d%d",&k,&n);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
sort(a+,a++n);
for(int i=;i<n;i++){
int l=i+,r=n;
int x=k-a[i];
int pos=lower_bound(a+i+,a+n+,x)-a;
if(a[pos]!=x)continue;
else printf("%d %d\n",a[i],a[pos]),flag=;
}
if(!flag){
printf("No Solution");
return ;
}
return ;
}
AC代码 枚举+二分
G - 活动安排问题(贪心&线段覆盖)
有若干个活动,第i个开始时间和结束时间是[Si,fi),同一个教室安排的活动之间不能交叠,求要安排所有活动,最少需要几个教室?
Input第一行一个正整数n (n <= 10000)代表活动的个数。
第二行到第(n + 1)行包含n个开始时间和结束时间。
开始时间严格小于结束时间,并且时间都是非负整数,小于1000000000Output一行包含一个整数表示最少教室的个数。Sample Input
3
1 2
3 4
2 9
Sample Output
2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 10010
using namespace std;
int n;
bool vis[maxn];
struct node{
int s,t;
bool operator < (const node b)const{
return t>b.t;
}
}a[maxn];
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d%d",&a[i].s,&a[i].t);
sort(a+,a+n+);
memset(vis,,sizeof(vis));
int ans=;
while(){
int p,st;
bool flag=;
for(int i=;i<=n;i++){
if(!vis[i]){
p=i;
vis[p]=;
flag=;
break;
}
}
if(!flag)break;
ans++;st=p;
for(int i=st+;i<=n;i++){
if(!vis[i]&&a[i].t<=a[p].s){
vis[i]=;
p=i;
}
}
}
printf("%d",ans);
return ;
}
AC代码 贪心
H - Anigram单词(唯一分解定理)
一个单词a如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的Anigram,例如单词army和mary互为Anigram。现在给定一个字典,输入Q个单词,从给出的字典中找出这些单词的Anigram。
Input第1行:1个数N,表示字典中单词的数量。(1 <= N <= 10000)
第2 - N + 1行,字典中的单词,单词长度 <= 10。
第N + 2行:查询的数量Q。(1 <= Q <= 10000)
第N + 3 - N + Q - 2行:用作查询的单词,单词长度 <= 10。Output共Q行,输出Anigram的数量,相同的2个单词不算Anigram,如果没有输出0。Sample Input
5
add
dad
bad
cad
did
3
add
cac
dda
Sample Output
1
0
2
/*
首先定义a-z分别为从1开始的素数,例如a=2,b=3,c=5,d=7这样.
然后定义一个函数int Func(char* data)
然后函数里面对于每个单词的每个字母进行相乘,例如单词abc就等于5*2*3=30;返回30
然后再到字典里面去找与这个单词位数相同且Func返回值相同的单词就好了. 这个算法主要用到了一个数学界的定理,如果一个正整数是n个素数相乘的结果,那么这个正整数有且只有一组素数解.
定理证明过程
z = a1*a2*....*an.
用反证法,如果有解,那么
z = a1*a2*.....*an-2*b*c,(b c代表如果有其它解的情况)两式相除得到下面的 对于这个题来说,还要将答案减去字典中与该字符串相等的字符串个数
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
int su[],cnt,n;
map<string,int>q1;
map<long long,int>q2;
bool vis[];
int main(){
scanf("%d",&n);
for(int i=;i<=;i++){
if(!vis[i])su[++cnt]=i;
for(int j=;j<=cnt&&su[j]*i<=;j++){
vis[su[j]*i]=;
if(i%su[j]==)break;
}
}
long long ans=;
string s;
for(int i=;i<=n;i++){
cin>>s;
q1[s]++;
int len=s.length();
long long num=;
for(int j=;j<len;j++){
int x=s[j]-'a'+;
num*=x;
}
q2[num]++;
}
scanf("%d",&n);
for(int i=;i<=n;i++){
cin>>s;
int ans=;
int len=s.length();
long long num=;
for(int j=;j<len;j++){
int x=s[j]-'a'+;
num*=x;
}
ans=q2[num]-q1[s];
printf("%d\n",ans);
}
}
AC代码 唯一分解定理
I - 全排列 (搜索)
Input输入一个字符串S(S的长度 <= 9,且只包括0 - 9的阿拉伯数字)Output输出S所包含的字符组成的所有排列Sample Input
1312
Sample Output
1123
1132
1213
1231
1312
1321
2113
2131
2311
3112
3121
3211
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define maxn 10
using namespace std;
int q[maxn],n,a[maxn];
char s[maxn];
bool vis[maxn];
map<string,int>v;
void dfs(int pos){
if(pos==n+){
string c="";
for(int i=;i<=n;i++)c+=a[i]+'';
if(v[c])return;
v[c]=;
for(int i=;i<=n;i++)printf("%d",a[i]);
puts("");
return;
}
for(int i=;i<=n;i++){
if(!vis[i]){
vis[i]=;
a[pos]=q[i];
dfs(pos+);
vis[i]=;
}
}
}
int main(){
scanf("%s",s+);
n=strlen(s+);
for(int i=;i<=n;i++)q[i]=s[i]-'';
sort(q+,q+n+);
dfs();
}
75分 暴力
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[],n;
char s[];
int main(){
scanf("%s",s);
n=strlen(s);
for(int i=;i<n;i++)a[i]=s[i]-'';
sort(a,a+n);
do{
for(int i=;i<n;i++)cout<<a[i];
cout<<endl;
}while(next_permutation(a,a+n));
}
100分 next_permutation
J - 旋转字符串 (STL)
S[0...n-1]是一个长度为n的字符串,定义旋转函数Left(S)=S[1…n-1]+S[0].比如S=”abcd”,Left(S)=”bcda”.一个串是对串当且仅当这个串长度为偶数,前半段和后半段一样。比如”abcabc”是对串,”aabbcc”则不是。
现在问题是给定一个字符串,判断他是否可以由一个对串旋转任意次得到。
Input第1行:给出一个字符串(字符串非空串,只包含小写字母,长度不超过1000000)Output对于每个测试用例,输出结果占一行,如果能,输出YES,否则输出NO。Sample Input
aa
ab
Sample Output
YES
NO
/*
对串无论旋转多少次都是对串,所以直接判断当前字符串是否是对串即可
*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
string s;
int main(){
while(cin>>s){
int l=s.length();
if(l%!=){
puts("NO");
continue;
}
l/=;
string s1=s.substr(,l);
string s2=s.substr(l,l);
if(s1==s2)puts("YES");
else puts("NO");
}
return ;
}
100分
K - 畅通工程 (Tarjan)
Input测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。
Output对每个测试用例,在1行里输出最少还需要建设的道路数目。
Sample Input
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0
Sample Output
1
0
2
998
/*
答案=强联通分量个数-1
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1010
#define min(a,b) (a)<(b)?(a):(b)
using namespace std;
int n,m,num,head[maxn];
struct node{
int to,pre;
}e[maxn*maxn];
void Insert(int from,int to){
e[++num].to=to;
e[num].pre=head[from];
head[from]=num;
}
int dfn[maxn],low[maxn],st[maxn],top,cnt;
bool in[maxn];
bool Tarjan(int u){
cnt++;dfn[u]=low[u]=cnt;st[++top]=u;in[u]=;
for(int i=head[u];i;i=e[i].pre){
int v=e[i].to;
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(in[v])low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
while(st[top]!=u){
in[st[top]]=;
top--;
}
in[u]=;
top--;
}
}
int main(){
while(){
memset(in,,sizeof(in));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(head,,sizeof(head));
memset(e,,sizeof(e));
num=;cnt=;
scanf("%d",&n);
if(n==)return ;
scanf("%d",&m);
int x,y;
for(int i=;i<=m;i++){
scanf("%d%d",&x,&y);
Insert(x,y);Insert(y,x);
}
int sum=;
for(int i=;i<=n;i++){
if(!dfn[i]){
sum++;
Tarjan(i);
}
}
printf("%d\n",sum-);
}
}
100分 Tarjan
vjudge个人赛 复习1的更多相关文章
- Trees on the level UVA - 122 复习二叉树建立过程,bfs,queue,strchr,sscanf的使用。
Trees are fundamental in many branches of computer science (Pun definitely intended). Current state- ...
- 矩阵乘法优化DP复习
前言 最近做毒瘤做多了--联赛难度的东西也该复习复习了. Warning:本文较长,难度分界线在"中场休息"部分,如果只想看普及难度的可以从第五部分直接到注意事项qwq 文中用(比 ...
- iOS总结_UI层自我复习总结
UI层复习笔记 在main文件中,UIApplicationMain函数一共做了三件事 根据第三个参数创建了一个应用程序对象 默认写nil,即创建的是UIApplication类型的对象,此对象看成是 ...
- vuex复习方案
这次复习vuex,发现官方vuex2.0的文档写得太简略了,有些看不懂了.然后看了看1.0的文档,感觉很不错.那以后需要复习的话,还是先看1.0的文档吧.
- 我的操作系统复习——I/O控制和系统调用
上篇博客介绍了存储器管理的相关知识——我的操作系统复习——存储器管理,本篇讲设备管理中的I/O控制方式和操作系统中的系统调用. 一.I/O控制方式 I/O就是输入输出,I/O设备指的是输入输出设备和存 ...
- 复习(1)【Maven】
终于开始复习旧知识了,有输入必然要有输出.输入和输出之间的内化过程尤为重要,在复习的同时,真正把学到的东西积淀下来,加深理解. Maven项目概念与配置 Maven是一个项目管理和综合工具.Maven ...
- 《CSS权威指南》基础复习+查漏补缺
前几天被朋友问到几个CSS问题,讲道理么,接触CSS是从大一开始的,也算有3年半了,总是觉得自己对css算是熟悉的了.然而还是被几个问题弄的"一脸懵逼"... 然后又是刚入职新公司 ...
- JS复习--更新结束
js复习-01---03 一 JS简介 1,文档对象模型 2,浏览器对象模型 二 在HTML中使用JS 1,在html中使用<script></script>标签 2,引入外部 ...
- jQuery 复习
jQuery 复习 基础知识 1, window.onload $(function(){}); $(document).ready(function(){}); 只执行函数体重的最后一个方法,事 ...
随机推荐
- python3用pdfminer3k在线读取pdf文件
import importlib import sys import random from urllib.request import urlopen from urllib.request imp ...
- 基础 PHP 语法
PHP 脚本在服务器上执行,然后向浏览器发送回纯 HTML 结果. 基础 PHP 语法 PHP 脚本可放置于文档中的任何位置. PHP 脚本以 <?php 开头,以 ?> 结尾: < ...
- .NET ViewState对于画面的速度影响
最近开发一个.NET网站,发现有一个画面的交互特别缓慢,查了很多原因都没查到 最后终于知道,是因为画面的ViewState用的过多,其中有一个ViewState保存的数据相对而言比较大,导致了画面的运 ...
- 一个关于前端页面的小标签<tbody>
我们有时候希望将表格的内容分为多个模块,这时候就可以使用<tbody>标签,它是<table>的字标签,是<tr>的父标签,可以使用它达到一种设置样式的结果.
- (转)HLS协议,html5视频直播一站式扫盲
本文来自于腾讯bugly开发者社区,原文地址:http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=1277 视频直播这么火,再不学就 ou ...
- python 列表之队列
列表实现队列操作(FIFO),可以使用标准库里的 collections.deque,deque是double-ended quene的缩写,双端队列的意思,它可以实现从队列头部快速增加和取出对象. ...
- ACM学习历程—HDU1717 小数化分数2(gcd)
Description Ray 在数学课上听老师说,任何小数都能表示成分数的形式,他开始了化了起来,很快他就完成了,但他又想到一个问题,如何把一个循环小数化成分数呢? 请你写一个程序不但可以将普通小数 ...
- ACM学习历程—Hihocoder 1164 随机斐波那契(数学递推)
时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 大家对斐波那契数列想必都很熟悉: a0 = 1, a1 = 1, ai = ai-1 + ai-2,(i > 1). ...
- 开发工作之外的修炼Live笔记
“开发工作之外的修炼”这期Live分享了下列话题: [1] 如何发现自己的兴趣 [2] 财富.资源与被动收入 [3] 目标管理 [4] 快速做选择 [5] 时间管理 [6] 如何投资自己 >&g ...
- 参数化之利用CSV Data Set Config从文件读取参数并关联变量
众所周知,在进行接口测试的过程中,需要创建不同的场景(不同条件的输入,来验证不同的入参的返回结果).因而,在日常的自动化接口监控或商品监控等线上监控过程中,需要配置大量的入参来监控接口的返回是否正确. ...