模拟:
JOG 20200807 普及模拟赛题
漫步(jog.cpp/c/pas)
(1s,512MB)
【题目描述】
有 n 组人在一条无尽的小路上漫步,每组人都有一个初始位置和速度,一组人总是会以相同的速度进行漫步,且所有人漫步的方向都相同。
因为这是一条小路,所以当一个速度更快的赶上另一组速度较慢的人时,这两组会合并成一组,而合并成的这个新组的速度与原来两组中速度较慢的那组速度相同,他们会以这个速度继续往前跑。
当然跑到最后的时候,没有任何一组会与其他组再合并。这个时候还剩下几组人?
【输入格式】
第一行两个数 n,表示初始组数。
接下一行 n 行每行两个数 d、v,表示这组的初始位置和初始速度。
数据保证所有组初始位置不同,并且读入按从小到大的顺序给出。
【输出格式】
一行一个数 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;
}
```