鬼知道\(cjx\)从哪里扣的题目(特别是T2),感觉全是坑,T1卡精度,T2写压位高精才满分,T3机房的\(dalao\)们有\(inf\)种解法。。
T1 拖拉机
【题目描述】:
啦啦啦,宇宙级帅锅\(TYH\)(没错就是陶一刀)又开着他心爱的拖拉机上学去了,由于他魅力四射,一路上遇到很多妹子,这些妹子都非要跟着他,他也只好勉为其难。一开始\(TYH\)的拖拉机速度为\(1km/min\),但妹子的体重实在不忍直视,以至于当他带上\(i\)个妹子以后,他的速度会降到\(\frac{1}{(i + 1)}km/min\),例如当他带上\(1\)个妹子时,速度为\(\frac{1}{2}\),\(2\)个妹子时,速度为\(\frac{1}{3}\),以此类推。
\(TYH\)的\(RP\)是如此的好,上天总是在他到达整数距离或整数时刻的时候让一个妹子出现。\(TYH\)想知道他多久才能到学校。
【输入格式】:
第一行两个正整数\(n\),\(m\),表示妹子的数量和\(TYH\)距离学校的距离。
接下来\(n + 1\)行,每行有两种形式:
- \(Dist\) \(x\) 表示在距离到达 \(x\) \(km\)时出现一个妹子
- \(Time\) \(x\) 表示在时间到达 \(x\) \(min\)的时候出现一个妹子
【输出格式】:
一行一个数,表示\(TYH\)到达学校的时间,如果不能整除,直接输出整数部分。
【样例输入】:
2 20
Time 3
Dist 10
【样例输出】:
47
【数据范围】:
对于\(30\)%数据,\(1\) <= \(n\),\(m\) <= \(50\)
对于\(50\)%数据,\(1\) <= \(n\),\(m\) <= \(2000\)
对于\(100\)%数据,\(1\) <= \(n\),\(m\) <= \(200000\),\(0\) <= \(x\) <= \(1e9\)
思路:
直接模拟即可,判断属性分别为\(Time\)和\(Dist\)的妹子被遇到的先后顺序,然后直接\(pick\) \(up\)就可以了。注意判断哪些在学校之后的妹子,直接甩了不要。。反正陶一刀女朋友够。
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
char s[5];
const int MAXN = 200005;
double ti[MAXN],di[MAXN];
int main(){
int n;double m;scanf("%d%lf",&n,&m);
int t=0,d=0;
for(int i=1;i<=n;++i){
scanf("%s",s);
if(s[0] == 'T'){
double a;scanf("%lf",&a);
ti[++t] = a;
}
else{
double a;scanf("%lf",&a);
if(a >= m) continue;
di[++d] = a;
}
}
sort(ti+1,ti+1+t);
sort(di+1,di+1+d);
if(ti[1] >= m){
printf("%.0lf",m);
return 0;
}
int h1=1;int h2=1;double ans = 1.0;
double cost = 0.0;double DIS = 0.0;
while(h1!=t+1 || h2!=d+1){1.
double v = 1/ans*1.0;
if(DIS >= m) break;
if((ti[h1] - cost < (di[h2]-DIS)/v && h1!=t+1) || h2 == d+1){
DIS += (ti[h1]-cost)*v;
cost = ti[h1];
h1++;
ans+=1.0;
continue;
}
if((ti[h1] - cost > (di[h2]-DIS)/v && h2!=d+1) || h1 == t+1){
cost += (di[h2]-DIS)/v;
DIS = di[h2];
h2++;
ans+=1.0;
continue;
}
if(ti[h1] - cost == (di[h2]-DIS)/v - cost && h2!=d+1 && h1!=t+1){
cost = ti[h1];
DIS = di[h2];
h1++;h2++;ans+=2.0;
continue;
}
}
double v = 1/ans*1.0;
cost += (m - DIS)/v;
printf("%.0lf",floor(cost));
return 0;
}
T2 序列操作
【题面描述】:
\(CJJ\)被\(SCOI2012\)那道序列操作做吐了,于是他想出了一道简单的序列操作的题目自我安慰。
有一个包含\(n\)个数序列的\(A_i\),她想找出两个非空的集合\(S\)、\(T\)。
这两个集合要满足以下的条件:
- 两个集合中的元素都为整数,且都在\([1,n]\) 里,即\(S_i\),\(T_i\)∈\([1,n]\)。
- 对于集合\(S\)中任意一个元素\(x\),集合\(T\)中任意一个元素\(y\),满足\(x < y\)。
- 对于大小分别为p, q的集合S与T,满足:
\(A[s_1]\) \(xor\) \(A[s_2]\) \(xor\) \(A[s_3]\) ... \(xor\) \(A[s_p]\) =
\(A[t_1]\) \(and\) \(A[t_2]\) \(and\) \(A[t_3]\) ... \(and\) \(A[t_q]\)
上式中的\(xor\)和\(and\)分别表示位运算异或运算和与运算。
\(CJJ\)想知道一共有多少对这样的集合\((S,T)\),既然你都来了,就帮忙一起算一下吧。
【输入格式】:
第一行,一个整数\(n\)
第二行,\(n\)个整数,代表\(A_i\)
【输出格式】:
仅一行,表示最后的答案。
【样例输入】:
4
1 2 3 3
【样例输出】:
4
【数据范围】:
对于\(30\)%的数据, \(1 <= n <= 10\)
对于\(70\)%的数据, \(1 <= n <= 100\)
对于\(100\)%的数据,\(1 <= n <= 1000, 0 <= ai < 1024\)
思路:
这TM明明比序列操作还难好吗。表示当时题都没看懂:)
\(Dp\),两个数相等就相当于两个数的\(xor\)为\(0\)。设 \(f[i][j][k=0..2]\)代表 处理到第 \(i\) 个数,如果 \(k = 1\)代表\(and\)值为\(j\),如果\(k = 2\)代表\(xor\) 值为 \(j\),如果\(k = 0\)则代表一个元素都没取。所以很容易得到方程:
- \(f[i][j][0] = f[i + 1][j][0]\)
- \(f[i]\)[\(j\) & \(a_i\)]\([1]\) = \(f[i + 1][j][1] + f[i + 1][j][0] + f[i + 1][j\) & \(a_i\)]\([1]\)
- \(f[i][j\) ^ \(a_i2]\) = \(f[i + 1][j][1] + f[i + 1][j][2] + f[i + 1][j\) ^ \(a_i][2]\);
最后\(f[1][0][2]\)就是答案, 复杂度为\(O(n * 1024 * 3)\)
\(DP\)还可以分开用\(f[i][j]\)和\(g[i][j]\)表示前\(i\)个\(xor\)值为\(j\),后\(i\)个\(and\)值为\(j\)的方案数, 随后枚举分界点\(k\)来求总方案数。复杂度\(O(n * 1024 * 3)\)。
但是。。。。。。
没错你没有看错,没加高精度只有70dpts!!!
于是这道题还要愉快地加上高精度。。。
本人高精度写得丑,用了一下\(jacktang\)的
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define LL long long
#define gch getchar
#define pch putchar
using namespace std;
template <class X> inline void read(X &x){
x=0;char ch=gch();X f=1;
while(ch>'9' || ch<'0') {if(ch=='-') f=-1;ch=gch();}
while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-48;ch=gch();}
x*=f;
}
const int MAXN=1000+5;
LL n,a[MAXN];
struct huge{
#define N_huge 110
#define base 100000000
static char s[N_huge*10];
typedef long long value;
value a[N_huge];int len;
void clear(){len=1;a[len]=0;}
huge(){clear();}
huge(value x){*this=x;}
huge(char s[]){this->str(s);}
huge operator =(const huge &b){
len=b.len;for (int i=1;i<=len;++i)a[i]=b.a[i]; return *this;
}
huge operator +(const huge &b){
int L=len>b.len?len:b.len;huge tmp;
for (int i=1;i<=L+1;++i)tmp.a[i]=0;
for (int i=1;i<=L;++i){
if (i>len)tmp.a[i]+=b.a[i];
else if (i>b.len)tmp.a[i]+=a[i];
else {
tmp.a[i]+=a[i]+b.a[i];
if (tmp.a[i]>=base){
tmp.a[i]-=base;++tmp.a[i+1];
}
}
}
if (tmp.a[L+1])tmp.len=L+1;
else tmp.len=L;
return tmp;
}
huge operator -(huge b){
int L=len>b.len?len:b.len;huge tmp;
for (int i=1;i<=L+1;++i)tmp.a[i]=0;
for (int i=1;i<=L;++i){
if (i>b.len)b.a[i]=0;
tmp.a[i]+=a[i]-b.a[i];
if (tmp.a[i]<0){
tmp.a[i]+=base;--tmp.a[i+1];
}
}
while (L>1&&!tmp.a[L])--L;
tmp.len=L;
return tmp;
}
huge operator *(const huge &b)const{
int L=len+b.len;huge tmp;
for (int i=1;i<=L;++i)tmp.a[i]=0;
for (int i=1;i<=len;++i)
for (int j=1;j<=b.len;++j){
tmp.a[i+j-1]+=a[i]*b.a[j];
if (tmp.a[i+j-1]>=base){
tmp.a[i+j]+=tmp.a[i+j-1]/base;
tmp.a[i+j-1]%=base;
}
}
tmp.len=len+b.len;
while (tmp.len>1&&!tmp.a[tmp.len])--tmp.len;
return tmp;
}
/*huge operator *(const huge &b){
int L=len+b.len;huge tmp;
for (int i=1;i<=L;++i)tmp.a[i]=0;
for (int i=1;i<=len;++i)
for (int j=1;j<=b.len;++j)
tmp.a[i+j-1]+=a[i]*b.a[j];
tmp.len=len+b.len;
for (int i=1;i<tmp.len;++i)
if (tmp.a[i]>=base){
tmp.a[i+1]+=tmp.a[i]/base;
tmp.a[i]%=base;
}
while (tmp.len>1&&!tmp.a[tmp.len])--tmp.len;
return tmp;
}*/
pair<huge,huge> divide(const huge &a,const huge &b){
int L=a.len;huge c,d;
for (int i=L;i;--i){
c.a[i]=0;d=d*base;d.a[1]=a.a[i];
//while (d>=b){d-=b;++c.a[i];}
int l=0,r=base-1,mid;
while (l<r){
mid=(l+r+1)>>1;
if (b*mid<=d)l=mid;
else r=mid-1;
}
c.a[i]=l;d-=b*l;
}
while (L>1&&!c.a[L])--L;c.len=L;
return make_pair(c,d);
}
huge operator /(value x){
value d=0;huge tmp;
for (int i=len;i;--i){
d=d*base+a[i];
tmp.a[i]=d/x;d%=x;
}
tmp.len=len;
while (tmp.len>1&&!tmp.a[tmp.len])--tmp.len;
return tmp;
}
value operator %(value x){
value d=0;
for (int i=len;i;--i)d=(d*base+a[i])%x;
return d;
}
huge operator /(const huge &b){return divide(*this,b).first;}
huge operator %(const huge &b){return divide(*this,b).second;}
huge &operator +=(const huge &b){*this=*this+b;return *this;}
huge &operator -=(const huge &b){*this=*this-b;return *this;}
huge &operator *=(const huge &b){*this=*this*b;return *this;}
huge operator /=(const huge &b){*this=*this/b;return *this;}
huge operator %=(const huge &b){*this=*this%b;return *this;}
huge &operator ++(){huge T;T=1;*this=*this+T;return *this;}
huge &operator --(){huge T;T=1;*this=*this-T;return *this;}
huge operator ++(int){huge T,tmp=*this;T=1;*this=*this+T;return tmp;}
huge operator --(int){huge T,tmp=*this;T=1;*this=*this-T;return tmp;}
huge operator +(value x){huge T;T=x;return *this+T;}
huge operator -(value x){huge T;T=x;return *this-T;}
huge operator *(value x){huge T;T=x;return *this*T;}
//huge operator /(value x){huge T;T=x;return *this/T;}
//huge operator %(value x){huge T;T=x;return *this%T;}
huge operator *=(value x){*this=*this*x;return *this;}
huge operator +=(value x){*this=*this+x;return *this;}
huge operator -=(value x){*this=*this-x;return *this;}
huge operator /=(value x){*this=*this/x;return *this;}
huge operator %=(value x){*this=*this%x;return *this;}
bool operator ==(value x){huge T;T=x;return *this==T;}
bool operator !=(value x){huge T;T=x;return *this!=T;}
bool operator <=(value x){huge T;T=x;return *this<=T;}
bool operator >=(value x){huge T;T=x;return *this>=T;}
bool operator <(value x){huge T;T=x;return *this<T;}
bool operator >(value x){huge T;T=x;return *this>T;}
huge operator =(value x){
len=0;
while (x)a[++len]=x%base,x/=base;
if (!len)a[++len]=0;
return *this;
}
bool operator <(const huge &b){
if (len<b.len)return 1;
if (len>b.len)return 0;
for (int i=len;i;--i){
if (a[i]<b.a[i])return 1;
if (a[i]>b.a[i])return 0;
}
return 0;
}
bool operator ==(const huge &b){
if (len!=b.len)return 0;
for (int i=len;i;--i)
if (a[i]!=b.a[i])return 0;
return 1;
}
bool operator !=(const huge &b){return !(*this==b);}
bool operator >(const huge &b){return !(*this<b||*this==b);}
bool operator <=(const huge &b){return (*this<b)||(*this==b);}
bool operator >=(const huge &b){return (*this>b)||(*this==b);}
void str(char s[]){
int l=strlen(s);value x=0,y=1;len=0;
for (int i=l-1;i>=0;--i){
x=x+(s[i]-'0')*y;y*=10;
if (y==base)a[++len]=x,x=0,y=1;
}
if (!len||x)a[++len]=x;
}
void read(){
scanf("%s",s);this->str(s);
}
void print(){
printf("%d",(int)a[len]);
for (int i=len-1;i;--i){
for (int j=base/10;j>=10;j/=10){
if (a[i]<j)printf("0");
else break;
}
printf("%d",(int)a[i]);
}
}
};char huge::s[N_huge*10];
huge f[2][1025][2];
int cur;
int main(){
read(n);
for(int i=1;i<=n;++i) read(a[i]);
cur=0;
f[cur][a[n]][0]=1;
for(int i=n-1;i>=1;--i){
cur^=1;
for(int j=0;j<1024;++j) f[cur][j][0]=f[cur][j][1]=0;
f[cur][a[i]][0]=1;
for(int j=0;j<1024;++j){
f[cur][j][0]+=f[cur^1][j][0];
f[cur][j][1]+=f[cur^1][j][1];
f[cur][j & a[i]][0]+=f[cur^1][j][0];
f[cur][j ^ a[i]][1]+=f[cur^1][j][0]+f[cur^1][j][1];
}
}
f[cur][0][1].print();
return 0;
}
T3 天神下凡
不知道为神马取个这么高端的名字,就是\(vijos\)上的原题。。
月光的魔法
题面就不赘述了,我在\(vijos\)上也发了题解的,搬运过来算了。。
思路:
考虑一种新方法:括号匹配。
对于每一个圆,记录其左右分别能到达的最远点\(l\) , \(r\)。
显然 \(l\) = \(O\)(圆心) - \(R\)(半径); \(r = O + R\)。分别为左括弧和右括弧
然后得到一个\(2n\)的数组。
对于任意一个圆,其贡献仅有可能为两种:\(1\)或\(2\),其中\(1\)不必解释,当一个圆被其他圆沿半径方向分为两半,其贡献则为\(2\)。
则考虑括弧匹配,对于任意一个左括弧,记录其增加值\(add\)。有以下情况:
- 对于连续两个 \((\) ,他们的坐标相同,则前面一个的\(add\)暂时为\(1\)。
- 对于 \()\) 的出现,在栈中弹出第一个元素并把他的\(add\)\(+1\)记录到答案
- 对于连续的两个 \()\) 的出现,且坐标相同,则栈顶的 \((\) \(add\)暂时为\(1\)
- 对于连续的 \()\) 和 \((\) 出现,若坐标相同,则栈顶的 \((\) \(add\)暂时为\(1\)。
非以上情况所述,\(add\)均为\(0\)。
最后答案\(+1\),表示最外面的区域。复杂度\(O(nlogn + 2n)\)
#include<cstdio>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int n;
const int MAXN = 300005;
struct point{
int l,r,val,add;
}p[MAXN<<1];point s[MAXN<<1];point p1,p2;
inline bool cmp(const point a,const point b){
if(a.val == b.val) return a.r > b.r;
else return a.val < b.val;
}
inline void read(int&x){
x = 0;
bool flag = false;
char c = getchar();
while (c<'0'||c>'9'){
if (c == '-')
flag = true;
c = getchar();
}
while (c>='0'&&c<='9'){
x = x*10+c-'0';
c = getchar();
}
if (flag)
x = -x;
}
int main(){
read(n);int u = 0;
for(int i=1;i<=n;++i){
int o,r;read(o);read(r);
p1.val = o + r;p2.val = o - r;
p1.r = 1;p1.l = 0;p2.r = 0;p2.l = 1;
p1.add = p2.add = 0;
p[++u] = p1;
p[++u] = p2;
}
sort(p+1,p+1+u,cmp);int tot=0;
s[++tot] = p[1];int ans = 0;
int last = inf;
for(int i=2;i<=u;++i){
if(p[i].l){
if(p[i].val == s[tot].val) s[tot].add = 1;
if(last != inf){
if(p[i].val != last) s[tot].add = 0;
}
last = inf;
s[++tot] = p[i];
}
if(p[i].r){
if(last == inf) last = p[i].val;
else{
if(p[i].val != last) s[tot].add = 0;
last = p[i].val;
}
ans += (1 + s[tot].add);
tot--;
}
}
printf("%d",ans+1);
return 0;
}
然而>_>
机房\(dalao\)多,做法千万种,种种踩\(std\)
比如:(蜜汁二分\(rank1\))
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define inl inline
#define ll long long
template<class X>inl void read(X &x)
{
X f=1;x=0;char c=getchar();
for(;c>'9'||c<'0';c=getchar())if(c=='-')f=-1;
for(;c<='9'&&c>='0';c=getchar())x=x*10+c-'0';
x=x*f;
}
#define inf 1061109567
#define N 300005
#define rgs register
struct cer{int l,r;}c[N];
inl bool cmp(const cer &a,const cer &b){return (a.l^b.l)?(a.l<b.l):(a.r>b.r);}
int n;
int r[N];//r:(最大的)右边缘外切圆;
int findr(int x)
{
int L=x+1,R=n,goal=c[x].r,ans=0;
while(L<=R)
{
int mid(L+R>>1);
if(c[mid].l==goal)ans=mid;
if(c[mid].l>=goal)R=mid-1;
else L=mid+1;
}
if(ans)while(c[ans-1].l==c[ans].l)--ans;
r[x]=ans;
return ans;
}
int main()
{
memset(r,-1,sizeof r);
read(n);
for(rgs int i=1;i<=n;++i)
{
int x,r;
read(x),read(r);
c[i].l=x-r,c[i].r=x+r;
}sort(c+1,c+1+n,cmp);
rgs int ans=1;
for(rgs int i=1;i<=n;++i)
{
int x=i,Re=c[i].r;
if(c[x+1].l^c[x].l){++ans;continue;}
++x;
while(x)
{
x=(~r[x])?r[x]:findr(x);
if(c[x].r==Re){++ans;break;}
}++ans;
}
printf("%d",ans);
return 0;
}
或者:线段树+离散化(\(4000ms+\))
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define LL long long
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define gch getchar
#define pch putchar
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
template <class X> inline void read(X &x){
x=0;char ch=gch();X f=1;
while(ch>'9' || ch<'0') {if(ch=='-') f=-1;ch=gch();}
while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-48;ch=gch();}
x*=f;
}
template <class X> inline void print(X x){
if(x<0) pch('-'),x=-x;
if(x>9) print(x/10);
pch(x%10+48);
}
const int MAXN=300000+5;
int n,hash[MAXN<<1],hash_cnt,cnt;
struct Segment{
int l,r,len;
bool operator < (const Segment &x)const{
return len<x.len;
}
}s[MAXN];
inline int pos(int x){
return lower_bound(hash+1,hash+1+hash_cnt,x)-hash;
}
struct Segment_tree{
int cou[MAXN<<3];
inline void cover(int now,int l,int r,int L,int R){
if(L<=l && r<=R){cou[now]++;return;}
int mid=(l+r)>>1;
if(L<=mid) cover(ls,l,mid,L,R);
if(R>mid) cover(rs,mid+1,r,L,R);
cou[now]=min(cou[ls],cou[rs]);
}
inline bool check(int now,int l,int r,int L,int R){
if(L<=l && r<=R) return cou[now];
int mid=(l+r)>>1;
if(L<=mid && R>mid) return check(ls,l,mid,L,R)&&check(rs,mid+1,r,L,R);
else if(L<=mid) return check(ls,l,mid,L,R);
else if(R>mid) return check(rs,mid+1,r,L,R);
}
}T;
int main(){
read(n);
for(int i=1;i<=n;++i){
int x,y;read(x);read(y);
s[i].l=x-y;s[i].r=x+y-1;
s[i].len=y<<1;
hash[++cnt]=s[i].l;
hash[++cnt]=s[i].r;
}
sort(hash+1,hash+1+cnt);
hash_cnt=unique(hash+1,hash+1+cnt)-(hash+1);
for(int i=1;i<=n;++i){
s[i].l=pos(s[i].l);
s[i].r=pos(s[i].r);
}
sort(s+1,s+1+n);
int ans=n+1;
for(int i=1;i<=n;++i){
if(T.check(1,1,hash_cnt,s[i].l,s[i].r)) ans++;
T.cover(1,1,hash_cnt,s[i].l,s[i].r);
}
print(ans);
return 0;
}
\(or\) 并查集大法好
#include<map>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 300005
using namespace std;
inline int read(){
int e=0,ch=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')ch=-1;c=getchar();}
while(c>='0'&&c<='9'){e=e*10+(c-48);c=getchar();}
return e*ch;
}
int n,ans,m,c,d,cnt;
int b[N<<1],fa[N<<1];
struct node{
int l,r;
}e[N];
struct ndqe{
int rank,w,id,to;
}pp[N<<1];
inline int fin(int x){
if(fa[x]!=x) return fa[x]=fin(fa[x]);
return x;
}
inline bool cmp(ndqe x,ndqe y){
return x.w<y.w;
}
inline bool cmp2(node x,node y){
return (x.r-x.l)<(y.r-y.l);
}
int main(){
n=read();
ans=n+1;
for(int i=1;i<=n;++i){
c=read();
d=read();
e[i].l=c-d;
e[i].r=c+d;
pp[++cnt].id=i;
pp[cnt].w=c-d;
pp[cnt].to=1;
pp[++cnt].id=i;
pp[cnt].w=c+d;
pp[cnt].to=0;
}
sort(pp+1,pp+cnt+1,cmp);
pp[1].rank=1;
for(int i=2;i<=cnt;++i){
if(pp[i].w>pp[i-1].w) pp[i].rank=pp[i-1].rank+1;
else pp[i].rank=pp[i-1].rank;
}
for(int i=1;i<=cnt;++i){
if(pp[i].to) e[pp[i].id].l=pp[i].rank;
else e[pp[i].id].r=pp[i].rank;
}
for(int i=1;i<=pp[cnt].rank;++i) fa[i]=i;
sort(e+1,e+n+1,cmp2);
for(int i=1;i<=n;++i){
int l=e[i].l,r=e[i].r;
l=fin(l),r=fin(r);
if(l==r) ans++;
else fa[l]=r;
}
printf("%d",ans);
return 0;
}
还有一个奇怪的栈模拟
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
struct Info {
int left,r,o,right,ind;
Info(int o,int r) {
this->left = o - r;
this->right = o + r;
this->r = r;
this->o = o;
}
Info(Info info,int ind) {
this->ind = ind;
this->left = info.left;
this->right = info.right;
this->r = info.r;
this->o = info.o;
}
Info(){
}
bool operator<(Info info) const {
if (left == info.left)
return r>info.r;
else return left<info.left;
}
};
Info infos[300005];
stack<Info> sta;
int sizes[300005];
void read(int&x){cin>>x;}
int main() {
int n;
read(n);
for (int i = 0;i<n;i++) {
int o,r;
read(o);
read(r);
infos[i] = Info(o,r);
}
sort(infos,infos+n);
int ans = 2;
sta.push(Info(infos[0],0));
for (int i = 1;i<n;i++) {
ans++;
Info info = infos[i];
Info top = sta.top();
while (info.left>=top.right&&!sta.empty()) {
sta.pop();
if (!sta.empty())
top = sta.top();
}
if (!sta.empty())
sizes[top.ind] += info.r*2;
sta.push(Info(info,i));
}
for (int i = 0;i<n;i++)
if (sizes[i]==infos[i].r*2)
ans++;
cout<<ans<<endl;
}