Jeanny
寂兮,寥兮,独立不改,周行而不殆

模拟:

JOG 20200807 普及模拟赛题

 

漫步(jog.cpp/c/pas)

1s,512MB)

【题目描述】

   n 组人在一条无尽的小路上漫步,每组人都有一个初始位置和速度,一组人总是会以相同的速度进行漫步,且所有人漫步的方向都相同

为这是一条小路,所以当一个速度更快的赶上另一组速度较慢的人时,这两组会合并成一组,而合并成的这个新组的速度与原来两组中速度较慢的那组速度相同,们会以这个速度继续往前跑。

当然跑到最后的时候,没有任何一组会与其他组再合并。这个时候还剩下几组

【输入格式】

第一行两个数 n,表示初始组数

接下一行 n 行每行两个数 dv表示这组的初始位置和初始速度

数据保证所有组初始位置不同,并且读入按从小到大的顺序给出。

【输出格式】

一行一个数 ans , 表示最后还剩下几组

【样例输入】

5

0  1

1  2

2  3

3  2

6  1

【样例输出】

2

【数据范围】

对于 30 % 的数据,n ≤ 2000。

对于 100 % 的数据,n ≤ 10^5,0 ≤ d ≤ 10^9,1 ≤ v ≤ 10^9。

模拟写法:

#include<cstdio>
using namespace std;
int n,v[100005],ans=1,x;
int main(){
    freopen("jog.in","r",stdin);
    freopen("jog.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%*d%d",&v[i]);
    x=v[n];
    for(int i=n-1;i;--i)
        if(v[i]<=x) ++ans,x=v[i];
    printf("%d",ans);
    return 0;
}

 

单调队列入门:

#include <bits\stdc++.h>
using namespace std;

const int kMaxn = 111111;

int n, a[kMaxn], tail = 0;

int main() {
    freopen("jog.in", "r", stdin);
    freopen("jog.out", "w", stdout);
    scanf("%d", &n);
    while (n--) {
        int t;
        scanf("%*d%d", &t);
        while (tail && t < a[tail]) {//维护一个单调不降的队列,最终队列里元素的个数就是答案
            --tail;//例如:1 2 3 3,说明肯定定都追不上
        }
        a[++tail] = t;
    }
    printf("%d\n", tail);
    return 0;
}

 

P3111 [USACO14DEC]Cow Jog S

 

有N (1 <= N <= 100,000)头奶牛在一个单人的超长跑道上慢跑,每头牛的起点位置都不同。由于是单人跑道,所有他们之间不能相互超越。当一头速度快的奶牛追上另外一头奶牛的时候,他必须降速成同等速度。我们把这些跑走同一个位置而且同等速度的牛看成一个小组。

 

请计算T (1 <= T <= 1,000,000,000)时间后,奶牛们将分为多少小组。

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
long long n,t,last[100005];
struct cow{
    long long x,v;
}a[100005];
int main(){
    cin >> n >> t;
    for(int i=1;i<=n;i++){
        cin >> a[i].x >> a[i].v;
        last[i]=a[i].x+a[i].v*t;
    }
    long long res=1, la = last[n];//long long 
    for(int i=n-1;i>=1;i--){
        if(last[i] < la){
            la = last[i];
            res++;
        }
    }
    cout<< res<<endl;
    return 0;
}

同样维护一个单调队列:

#include<cstdio>
#include<iostream>
using namespace std;
const int manx=101000;
long long que[manx<<1];
int tail=0;
long long ans;
void push(long long val){
	while(que[tail]>=val&&tail)	tail--;
	que[++tail]=val;
}
int main(){
	int n,t;
	scanf("%d%d",&n,&t);
	long long a,b;
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&a,&b);
		push(a+b*t);
	}
	printf("%d\n",tail);
	return 0;
}

P2058 [NOIP2016 普及组] 海港

//队列
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,t,k,cnt,vis[100005],x,front = 1,tail;
struct Node{
    int val, tim;
}q[300005];
int main(){
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        scanf("%d%d",&t,&k);
        for(int j = 1; j <= k; j++){
            scanf("%d",&x);
            if(!vis[x]) cnt++;
            q[++tail].val = x; vis[x]++;
            q[tail].tim = t;
        }
        while(q[front].tim <= t - 86400){
            vis[q[front].val]--;
            if(!vis[q[front].val]) cnt--;
            front++;
        }
        printf("%d\n", cnt);
    }
    return 0;
}

 

 

烦恼的高考志愿

o(n)的做法 //by yxm123456

#include<bits/stdc++.h>
using namespace std ;
int ans , n , m , sh[100005] , st[100005] ;
bool cmp(int x , int y){
    return x < y ;
}
int main(){
    scanf("%d%d" , &m , &n) ;
    memset(sh , 1 , sizeof sh) ;
    for(int k=1 ; k<=m ; k++){
        scanf("%d" , &sh[k]) ;
    }
    sort(sh+1 , sh+1+m , cmp) ;
    for(int k=1 ; k<=n ; k++){
        scanf("%d" , &st[k]) ;
    }
    sort(st+1 , st+1+n , cmp) ;
    int i=1 , j=1 ;
    while(i<=m && j<=n){
        int x = abs(sh[i] - st[j]) ;
        int y = abs(sh[i+1] - st[j]) ;
//        cout << x << " " << y << " " << i << " " << j << "   " ; 
        if(y<=x){
            i++ ;
        }else{
            ans += x ;
            j++ ;
        }
    }
    printf("%d\n" , ans) ;
    
    return 0 ;
}

 

P1024 [NOIP2001 提高组] 一元三次方程求解

步长为1的两端,进行二分。 为什么是eps(k+2)

#include<bits/stdc++.h>
using namespace std ;
double a , b , c , d , ans , l , r , mid ;
double f(double x){
    return  x*x*x*a + x*x*b + x*c + d ;
}
int main(){
    scanf("%lf%lf%lf%lf" , &a , &b , &c , &d) ;
    for(double i=-100 ; i<100 ; i++){
        l = i ;
        r = i+1 ;
        if(f(l)==0) printf("%.2lf " , l) ;
        if(f(l)*f(r)>=0) continue ;
        while(l + 0.0001 < r){
            mid = (l+r)/2 ;
            if(f(mid)*f(r)>0){
                r = mid ;
            }else{
                l = mid ;
            }
        }
        printf("%.2lf " , l) ;
    }
    return 0 ;
} 

优秀暴力

i+=0.001,因为会四舍五入,所以不是+0.01
#include<iostream>
#include<cstdio>
using namespace std;
double a,b,c,d,a1,b1,c1,d1;// 题目要的数据是小数点后2位所以定义首先用double
int num;// num用来记录解的个数 因为一元三次方程只有三个解  解达到三个以后就break掉 减少多余循环
int main()
{
    scanf("%lf%lf%lf%lf",&a,&b,&c,&d);// double类型用 lf 输入哦
    for(double i=-100.00;i<=100.00;i+=0.001)// 最后结果保存两位数 所以这里i每次加0.001(n只有100所以暴不了)
    {
        double l=i,r=i+0.001;
        if((a*l*l*l+b*l*l+c*l+d)*(a*r*r*r+b*r*r+c*r+d)<0)// 若存在两个数x1,x2且x1<x2,f(x1)*f(x2)<0 则方程解肯定在x1~x2范围内   基本数学原理
        printf("%.2f ",l),num++;// 小数点后两位输出
        if(num==3) break;// 解达到三个break掉
    }
    return 0;
}

 P5650 基础字符串练习题

考察:前缀和。

题目描述

给定长度非零的非空 01 串 SSS。

找出 S的非空连续子串 T满足串中 0 的个数减去 1 的个数最大。

你只需要输出最大值即可。

输入格式

一行一个 01 串表示 SSS。

输出格式

一行一个数表示答案。

// 1 -1 -1 -1 -1 -1 1 1 -1 1 -1
//考察 前缀和 0->1 1->-1
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
string s;
int a[100005], mn, ans, sum[100005];
int main(){
    cin>>s;
    int n = s.length();
    a[0] = sum[0] = mn = ans = (s[0] - '0' == 0 ? 1 : -1);
    mn = min(ans, 0);
    for(int i = 1; i < n; i++){
        a[i] = s[i] - '0';
        a[i] = (a[i] == 0 ?  1 : -1);
        sum[i] = sum[i-1] + a[i];//从1开始,否则越界
        ans = max(ans, sum[i] - mn);
        mn = min(mn, sum[i]);
    }
    cout<<ans<<endl;
    return 0;
}
/*
111111
0 1  0 0 0  0  1  1  0
1 -1 1 1 1  1 -1  -1 1
1 0  1 2 3  4

0 0
1 1
*/

 P1944 最长括号匹配

考察:栈的使用

注意:栈为空,取栈首,CE

教训:一开始栈里面存的是字符,后面发现寸位置更加,但是忘了修改栈里面的类型,心痛!

定义如下规则序列(字符串):

1.空序列是规则序列;

2.如果S是规则序列,那么(S)和[S]也是规则序列;

3.如果A和B都是规则序列,那么AB也是规则序列。

例如,下面的字符串都是规则序列:

(),[],(()),([]),()[],()[()]

而以下几个则不是:

(,[,],)(,()),([()

现在,给你一些由‘(’,‘)’,‘[’,‘]’构成的序列,你要做的,是补全该括号序列,即扫描一遍原序列,对每一个右括号,找到在它左边最靠近它的左括号匹配,如果没有就放弃。在以这种方式把原序列匹配完成后,把剩下的未匹配的括号补全。

// 第一种思路:
// ( [ (  ] [ ( )  ]  ]  ( )
// 1 2 1 -2 2 1 -1 -2 -2 -1 1
// 1 3 4  2 4 5 4  4  2  1  2
// 改进?改变?
// )   )( )(   (   )  ) (  )  )
// -1 -1  1  1   1  -1  -1  1  -1 -1
// -1 -2  1  2   3  2   1   2  1
// 弹出来
//
// (())((()
//
// if(top() == "(") q.pop();
//
// ( [ (  ] [ ( ) ] [] [ () ( () ]
//  (  [  (  )  ]
    // 1  2  3  4
// ( [ ( ]

/*
(  [  (  ]  [  (  )  ]  [  ]  (   )
0  1  2  3  4  5  6  7  8  9  10 11
([(][()][]()
*/

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
string s;
stack<int> q;
int f[10000005], ans;
int main(){
    memset(f, 0x7f, sizeof f);
    cin>>s;
    int len = s.length();
    for(int i = 0; i < len; i++){
        if(s[i] == '(' || s[i] == '[') q.push(i);
        else if(s[i] == ')'){
            if(!q.size()) q.push(i);//
            else if(s[q.top()] == '('){
                q.pop();
                if(!q.size()) f[i] = -1;
                else f[i] = q.top();
            }
            else q.push(i);
        }
        else if(s[i] == ']'){
            if(!q.size()) q.push(i);
            if(s[q.top()] == '['){
                q.pop();
                if(!q.size()) f[i] = -1;
                else f[i] = q.top();
            }
            else q.push(i);
        }
    }
    int bg = 0, ed = 0, mxlen = 0;
    for(int i = 0; i <= len; i++){
        if(i - f[i] > mxlen){
            bg = f[i] + 1, ed = i;
            mxlen = i - f[i];
        }
    }
    if(mxlen == 0) return 0;
    for(int i = bg; i <= ed; i++) cout<<s[i];
    return 0;
}
/*
()[]
()[]

((()))[][[]][][]([][][][]]]][]][
((()))[][[]][][]
*/

 第二种写法:

dp

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100000+10;
char st[maxn];
int ans;
int dp[maxn];
int main()
{
    scanf("%s",st+1);int len=strlen(st+1);
    for(int i=1;i<=len;i++)
    {
        if(st[i]=='(' || st[i]=='[')continue;
        if(st[i]==')' || st[i]==']')
        {
            if((st[i]==')' && st[i-1-dp[i-1]]=='(') || (st[i]==']' && st[i-1-dp[i-1]]=='['))
            {
                dp[i]=dp[i-1]+2+dp[i-2-dp[i-1]];
                ans=max(ans,dp[i]);
            }
        }
    }
    for(int i=1;i<=len;i++)
        if(dp[i]==ans)
        {
            for(int j=i-ans+1;j<=i;j++)printf("%c",st[j]); return 0;
        }
}

 

借教室

o(m+n)的方法,撤销

```

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define int long long
#define N 1000005
using namespace std;
int n, m, b[N], a[N], sum[N], q, t[N];
struct Node{
    int l,r,x;
}c[N];
signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i = 1; i <= n; i++){
        scanf("%lld",&a[i]);
        b[i] = a[i] - a[i-1];
    }
    for(int i = 1; i <= m; i++){
        scanf("%lld%lld%lld",&c[i].x, &c[i].l, &c[i].r);
        b[c[i].l] -= c[i].x;
        b[c[i].r + 1] += c[i].x;
    }
    int j = m;
    for(int i = 1; i <= n; i++){
        sum[i] = sum[i-1] + b[i];
        while(sum[i] < 0){
            b[c[j].l] += c[j].x;
            b[c[j].r + 1] -= c[j].x;
            if(i >= c[j].l && i <= c[j].r)
                sum[i] += c[j].x;
            j--;
        }
    }
    if(j == m) printf("0\n");
    else printf("-1\n%lld\n",j+1);
    return 0;
}

```

 

posted on 2022-07-24 15:06  Jeanny  阅读(82)  评论(0)    收藏  举报