Codeforces Round #561 (Div. 2)
题意:
给出 n 个数,问有多少点对(x,y)满足 |x-y| ≤ |x|,|y| ≤ |x+y|;
(x,y) 和 (y,x) 表示一种答案;
题解:
数形结合;
对于某数 x 查找满足条件 y 有多少个;
①x ≥ 0
y ∈ [x/2 , 2x] ∪ [ -2x , -x/2];
②x < 0
y ∈ [2x , -x/2] ∪ [-x/2 , -2x];
特别注意临界值 x/2 处;
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=2e5+50; 5 6 int n; 7 int x[maxn]; 8 9 int F(int a,int b)///查找数组x中有多少数位于[a,b]之间 10 { 11 if(a > b) 12 swap(a,b); 13 int t1=lower_bound(x+1,x+n+1,a)-x; 14 int t2=upper_bound(x+1,x+n+1,b)-x; 15 return t2-t1; 16 } 17 ll Solve() 18 { 19 sort(x+1,x+n+1); 20 21 ll ans=0; 22 for(int i=1;i <= n;++i) 23 { 24 int a,b; 25 if(x[i] >= 0) 26 a=(x[i]+1)/2; 27 else 28 a=(x[i]-1)/2;///不能写成(x[i]-1)>>1; 29 b=x[i]*2;///不能写成b=x[i]<<1; 30 ans += F(a,b); 31 ans += F(-a,-b); 32 ans--;///减掉x[i]本身 33 } 34 return ans>>1;///重复计算,除以2 35 } 36 int main() 37 { 38 scanf("%d",&n); 39 for(int i=1;i <= n;++i) 40 scanf("%d",x+i); 41 printf("%lld\n",Solve()); 42 43 return 0; 44 }
坑:
负数使用右移符号出错;
-2×2 ≠ -2<<1;
左移,右移只可以用到正整数上;
负数禁用位移运算;
题意:
定义“Cute Sequences”,如果序列x满足 ∀i∈[2 , n] xi=xi−1+xi−2+⋯+x1+ri (1 ≤ ri ≤ m),那么次序列为"Cute Sequences";
现给出你 a,b,m ,让你构造一个序列,满足:
①x[1] = a , x[n] = b;
②n ≤ 50;
③此序列为"Cute Sequences";
题解:
定义数组val[]存储最终的值;
看下面这段代码:
1 ll sum=a; 2 ll k=0; 3 val[++k]=a; 4 while(k <= 50) 5 { 6 if(val[k] >= b) 7 break; 8 9 val[++k]=sum+m; 10 sum += val[k]; 11 }
因为题目要求 k ≤ 50,所以,要先让其每次加最大的值 m ,找到使得 val[k] ≥ b 的最小的 k ;
那么多的部分 val[k]-b 该怎么办呢?
刚开始,每个数都会增加 m ,如果第 i 个数少加 x,有什么变化呢?
先通过上述小范围的数据看一下规律;
你会发现,如果第 i 个数少加 x,那么,对于第 j (j > i) 个数,就会少加2j-i-1x;
这样的话,就可以通过前面的数少加 x 使得第 k 个数 val[k] 变为 b;
不过在此之前你得确定 val[k] 可以减少为 b;
1 bool isSat(int k) 2 { 3 memcpy(tmp+1,val+1,k*sizeof(ll)); 4 for(int i=2;i <= k;++i) 5 { 6 ll x=m-1; 7 tmp[i] -= x; 8 for(int j=i+1;j <= k;++j)///i之后的数依次减少2^(j-i-1)*x,累加x即可 9 tmp[j] -= x,x += x; 10 if(tmp[k] <= b) 11 return true; 12 } 13 return tmp[k] <= b ? true:false; 14 }
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define mem(a,b) memset(a,b,sizeof(a)) 5 const int maxn=2e5+50; 6 7 int q; 8 ll a,b,m; 9 ll val[60]; 10 ll tmp[60]; 11 12 bool isSat(int k) 13 { 14 if(k == 1) 15 return true; 16 17 memcpy(tmp+1,val+1,k*sizeof(ll)); 18 for(int i=2;i <= k;++i) 19 { 20 ll x=m-1; 21 tmp[i] -= x; 22 for(int j=i+1;j <= k;++j) 23 tmp[j] -= x,x += x; 24 if(tmp[k] <= b) 25 return true; 26 } 27 return false; 28 } 29 void Solve() 30 { 31 ll sum=a; 32 ll k=0; 33 val[++k]=a; 34 while(k <= 50) 35 { 36 if(val[k] >= b) 37 break; 38 39 val[++k]=sum+m; 40 sum += val[k]; 41 } 42 43 if(k > 50 || !isSat(k)) 44 { 45 printf("-1\n"); 46 return ; 47 } 48 49 printf("%lld %lld",k,a); 50 for(int i=2;i < k;++i) 51 { 52 ll d=val[k]-b; 53 ll x=min(m-1,d/(1ll*1<<(k-i-1))); 54 55 val[i] -= x; 56 for(int j=i+1;j <= k;++j) 57 val[j] -= x,x += x; 58 59 printf(" %lld",val[i]); 60 } 61 if(k > 1) 62 printf(" %lld\n",b); 63 else 64 printf("\n"); 65 } 66 int main() 67 { 68 // freopen("C:/Users/14685/Desktop/stdin&&stdout/contest","r",stdin); 69 scanf("%d",&q); 70 while(q--) 71 { 72 scanf("%lld%lld%lld",&a,&b,&m); 73 Solve(); 74 } 75 return 0; 76 }
bug:
61~64最后输出语句,晚上重新敲的时候将其放到了for()里:
1 printf("%d %lld",k,a); 2 for(int i=2;i <= k;++i) 3 { 4 if(i == k) 5 { 6 printf(" %lld\n",b); 7 return ; 8 } 9 ll d=val[k]-b; 10 ll x=min(m-1,d/(1ll*1<<(k-i-1))); 11 12 val[i] -= x; 13 for(int j=i+1;j <= k;++j) 14 val[j] -= x,x += x; 15 16 printf(" %lld",val[i]); 17 }
一直是“Wrong answer on test 10”,debug了好一会,才发现,当 k = 1是,最后是有换行的;
但是,放到for()里就缺少一个换行;