大水题。最长连续递增子序列有多长。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 int main() 5 { 6 int n, a, rec = 0, len = 0, ans = 1; 7 scanf("%d",&n); 8 for(int i = 0; i < n; i++) 9 { 10 scanf("%d", &a); 11 if(a > rec) 12 { 13 rec = a, len++; 14 } 15 else 16 rec = a, len = 1; 17 ans = max(ans, len); 18 } 19 printf("%d\n",ans); 20 return 0; 21 }
这道题有点意思昂,问你有几对,满足巴拉巴拉。
先说一下一开始吧,我的做法是直接暴力两重for循环去做,明显TLE了。一开始没注意n²。
1 #include <cstdio> 2 typedef long long LL; 3 int a[100000+5]; 4 int main() 5 { 6 int n; 7 8 scanf("%d", &n); 9 LL ans = 0; 10 for(int i = 0; i < n; i++) 11 { 12 scanf("%d",a+i); 13 } 14 for(int i = 0; i < n; i++) 15 { 16 for(int j = i+1; j < n; j++) 17 { 18 LL tot = a[i] + a[j]; 19 while( (tot & 1) == 0) 20 tot >>= 1; 21 if(tot == 1) 22 ans++; 23 } 24 } 25 printf("%lld\n",ans); 26 return 0; 27 }
然后想啊,这TLE咋办,咱剪枝吧。个么,就加了一下这几句话。妄想着能砍掉大部分数据。
bool p1 = a[i] % 2; bool p2 = a[j] % 2; if( (p1 && !p2) || (!p1 && p2)) continue;
又光荣TLE了。这下给搞急了,还TLE啊。咋办呢,预处理了一个2的幂,然后二分查。
1 #include <cstdio> 2 typedef long long LL; 3 int a[100000+5]; 4 LL J[35]; 5 int main() 6 { 7 LL t = 2; 8 int p = 0; 9 while(t <= 2000000000 + 5) 10 { 11 J[p++] = t; 12 t <<= 1; 13 } 14 15 int n; 16 17 scanf("%d", &n); 18 LL ans = 0; 19 for(int i = 0; i < n; i++) 20 { 21 scanf("%d",a+i); 22 } 23 for(int i = 0; i < n; i++) 24 { 25 for(int j = i+1; j < n; j++) 26 { 27 bool p1 = a[i] % 2; 28 bool p2 = a[j] % 2; 29 if( (p1 && !p2) || (!p1 && p2)) continue; 30 LL tot = a[i] + a[j]; 31 32 int lb = -1, rb = 30; 33 while(rb - lb > 1) 34 { 35 int mid = (lb + rb) / 2; 36 if(tot == J[mid]) 37 {ans++;break;} 38 else if(tot > J[mid]) 39 lb = mid; 40 else 41 rb = mid; 42 } 43 } 44 } 45 printf("%lld\n",ans); 46 return 0; 47 }
没曾想,又TLE了,orz。。但是!这个预处理,发现一个事,这总共啊,能选的2的幂才30个左右。这就带来了后面的代码的思路。
但这个地方,咱们没认怂,还想。加了个2的幂的位运算的判断方法。
bool judge(LL n) { return (n>0) && (!(n&(n-1))); }
人不超时,妄少年啊,你就是死活不肯定动n²的大框架。下面学着点
咋办呢,刚刚不是说了吗这个数据范围,撑死就2的三十次。拿这个做文章。
数据的范围决定了,不能用数组,得用map记录。咋记录啊,ma[x]就代表x出现了几次。咱们就每次输进来个数,然后就检查
我2-x这个数有几个啊,4-x呢,8-x呢,16-x呢,是不是有一个算一个,统统记录到ans里头去啊。最后的统计结果是不是就是答案,又因为你是按输入的时候每输入一个,算一发有几个符合条件的,就间接满足了题目中j>i的要求啊。个么AC了咯。
1 #include <cstdio> 2 #include <map> 3 using namespace std; 4 typedef long long LL; 5 map<LL,LL>ma; 6 int main() 7 { 8 int n, x; 9 LL ans = 0; 10 scanf("%d",&n); 11 for(int i=0;i<n;i++) 12 { 13 scanf("%d",&x); 14 for(int j = 30 ; j >= 0; j--) 15 { 16 LL power = (LL) (1 << j); 17 ans += ma[power - x]; 18 } 19 ma[x]++; 20 } 21 printf("%lld",ans); 22 return 0; 23 }
然后看到AC后面跟了两个啥数据啊1996 ms 125000 KB,我去这么大啊。那下次不给你三秒的时间,给你1.5秒,你咋办,还能这么做不,明显又被卡成TLE了。咋办,能咋办,再想呗。那这样好不好,框架咱们不动它,还是n*30的复杂度。map咱们也不用了,这次改全部读进来,数组麻溜的存起来。来个排序。干啥呀,干嘛要排序呢。这不从n*30到nlogn了吗。
然后来了,刚刚那个,搜索2的幂-x的方法记得不。这次换个主角,map太贵了。lower_bound和upper_bound。思路不变,实现方法改了而已。跑了一遍样例,发现诶,不对啊,这个错了。
为啥。重复了。重复什么了,他每次会把自己算进去了,这是一方面,还有,它打乱了i和j,还要除以2。
好,这下又AC了,265 ms 200 KB。这就对了嘛看起来舒服多了。
1 #include <cstdio> 2 #include <map> 3 #include <algorithm> 4 using namespace std; 5 typedef long long LL; 6 int a[100000 + 50]; 7 int main() 8 { 9 int n; 10 scanf("%d", &n); 11 for(int i = 0; i < n; i++) 12 scanf("%d",a+i); 13 sort(a,a+n); 14 LL ans = 0; 15 for(int i = 0; i < n; i++) 16 { 17 for(int j = 30; j >= 0; j--) 18 { 19 LL temp = (1 << j) - a[i]; 20 int pos1 = lower_bound(a,a+n,temp) - a; 21 int pos2 = upper_bound(a,a+n,temp) - a; 22 ans += pos2 - pos1; 23 if(temp == a[i]) 24 ans--; 25 } 26 } 27 printf("%lld\n", ans/2); 28 return 0; 29 }
可是咱还得想啊,要是先想一开始就搞定i和j的先后咋整。
看高亮啊,可以调的参数。
int pos1 = lower_bound(a+i,a+n,temp) - a; int pos2 = upper_bound(a+i,a+n,temp) - a;
数据这么大,宝宝很害怕。
典型二分,随便搞。
注意
1 1
-1000000000
1000000000
这组数据把int爆了。。。 所以WA了。所以在longlong边缘的还是上longlong吧。其实是自己分析问题的时候,不够精准。二分的数据范围上判断出了问题。
另外半径是0到2倍的INF。而不是傻兮兮的-INF到INF,也不是0到INF。
1 #include <cstdio> 2 const int INF = 1000000000; 3 const int maxn = 100000 + 50; 4 typedef long long LL; 5 int city[maxn], tower[maxn]; 6 int n,m; 7 bool judge(LL r) 8 { 9 int cur = 0; 10 for(int i = 0; i < n; i++) 11 { 12 while(!(city[i] >= (LL) (tower[cur] - r) && city[i] <= (LL) (tower[cur] + r) ) ) 13 { 14 cur++; 15 if(cur == m ) return false; 16 } 17 } 18 return true; 19 } 20 int main() 21 { 22 scanf("%d%d", &n, &m); 23 for(int i = 0; i < n; i++) 24 { 25 scanf("%d", &city[i]); 26 } 27 28 for(int i = 0; i < m; i++) 29 { 30 scanf("%d", &tower[i]); 31 } 32 33 LL lb = -1, rb = 2 * INF + 5; 34 while(rb - lb > 1) 35 { 36 LL mid = (lb + rb) / 2; 37 if(judge(mid)) 38 { 39 rb = mid; 40 } 41 else 42 { 43 lb = mid; 44 } 45 } 46 printf("%lld\n",rb); 47 return 0; 48 }
数学题orz,这个公式很好推。思路也很容易想,直接分三种情况讨论,取最好的情况。
但是!宝宝们,你们有没有想过一件事,怎么取最好情况,有人说,这还不容易的一塌糊涂。。直接min两发不就好了。
你有没有考虑过d<k的时候,第二种情况可能是负数。反正测试数据里面,有两组数据经常会变负数。
d和k的大小关系!!!!!!!!!!!!!!!!!!!!!
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 typedef long long LL; 5 LL d,k,a,b,t,ans1,ans2,ans3,ans; 6 int main() 7 { 8 while(cin>>d>>k>>a>>b>>t) 9 { 10 //一直开车 11 if(d % k == 0) 12 ans1 = t * (d / k - 1) + d * a; 13 else 14 ans1 = t * (d / k ) + d * a; 15 ans = ans1; 16 //只开一次车就步行 17 if(d > k) 18 ans2 = k * a + (d - k) * b, ans = min(ans, ans2); 19 20 //最后一段路走路 21 if(d > k) 22 { 23 LL d_car = d / k * k; 24 LL d_per = d - d_car; 25 ans3 = d_car * a + d_per * b + t * (d_car / k - 1); 26 ans = min(ans, ans3); 27 } 28 cout<<ans<<endl; 29 } 30 return 0; 31 }