A - Yet Another Tetris ProblemCodeForces - 1324A
题意:给定一串长度为n的数组,当这串数组至少有一个数组大于 0 时进行如下操作:1、选择一个数+2 2、当这串数组每个数都大于 0 时,使这个数组每个数都减 1 ,直到有数小于等于0.然后在进行 1 操作,循环进行。问最后能否经过这些操作让这个数组上的数全部变为 0 。
思路:我感觉我当时写的时候思路是乱的,毕竟也好久没有写过题了,尴尬…….其实这个题就是思维题,你会发现只要数组同时出现奇数和偶数就不行,因为如果两个数相差 1 ,加上 2 是无法弥补的。
简单代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
int main(){
ios :: sync_with_stdio( false );
cin.tie( NULL );
int t, n, num, f;
cin >> t;
while( t-- ){
cin >> n;
int flag = 1;
for( int i = 0; i < n; i++ ){
cin >> num;
if( !i ){
f = num % 2;
}
else{
if( f != ( num % 2 ) ){
flag = 0;
}
}
}
if( flag ){
cout << "YES\n";
}
else{
cout << "NO\n";
}
}
return 0;
}
复杂代码(有点模拟的感觉,其实思路是乱的,碰巧过了罢了):
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
ios :: sync_with_stdio( false );
cin.tie( NULL );
int t, n, a[110];
cin >> t;
while( t-- ){
cin >> n;
int f = 0;
for( int i = 0; i < n; i++ ){
cin >> a[i];
if( a[i] > 0 ){
f = 1;
}
}
int k = 1;
while( f ){
f = 0;
sort( a, a + n );
if( ( a[n - 1] - a[0] ) % 2 != 0 ){
f = 0;
k = 0;
}
a[0] += 2;
sort( a, a + n );
int tp = a[0];
for( int i = 0; i < n && k; i++ ){
a[i] -= tp; //避免使用while增加复杂度
if( a[i] > 0 ){
f = 1;
}
}
// cout << a[0] << a[1] << a[2] << endl;
}
int p = 1;
for( int i = 0; i < n; i++ ){
if( a[i] != 0 ){
p = 0;
cout << "NO\n";
break;
}
}
if( p ){
cout << "YES\n";
}
}
return 0;
}
B - Yet Another Palindrome Problem
题意:给定一个长度为n的数组,判断这个数组是否存在长度大于等于 3 的子序列,这个子序列满足是个回文串。
思路:我们可以发现不管多长的回文串,从中间开始往两边同时遍历组成的串都是回文串,所以我们只需要找到3个数,满足 a X a 的形式即可,也就是找到左右相邻边上的数相等的数就可以满足条件。因为这道题数都不大,可以选择暴力查找右边a。
答案代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 5e3 + 10;
int t, n, a[N];
bool sh( int d, int num ){
for( int i = d; i < n; i++ ){
if( a[i] == num ){
return true;
}
}
return false;
}
int main(){
ios :: sync_with_stdio( false );
cin.tie( NULL );
cin >> t;
while( t-- ){
cin >> n;
for( int i = 0; i < n; i++ ){
cin >> a[i];
}
int f = 1;
for( int i = 1; i < n - 1; i++ ){
if( sh( i + 1, a[i - 1] ) ){
cout << "YES\n";
f = 0;
break;
}
}
if( f ){
cout << "NO\n";
}
}
return 0;
}
C - Frog Jumps
题意:给定一个字符串,且这个字符串只包含 'L'(向左跳) and 'R'(向右跳)(从 1 开始编号),一只青蛙从 0号 开起跳,问能跳到 n + 1号 位置的最小每次跳跃距离d。注意每次跳跃的距离只能小于等于d。
思路:这道题其实就是一个思维题,试想每次能推动青蛙往前的就是R,而如果跳到L,最后的结果就是跳到距离这个L最近的上一个R,这个可以直接看成从上一个R到下一个R,所以最后就变成R之间的最大距离(才可以保证到达 n + 1 ),而为了处理边界问题可以把 0号 和 n + 1号变成R.
答案代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 2e5 + 10;
char s[N];
int main(){
ios :: sync_with_stdio( false );
cin.tie( NULL );
int t;
cin >> t;
while( t-- ){
cin >> s + 1;
s[0] = 'R';
int slen = strlen( s );
// 注意用 char 数组最好使用 strlen函数(计算数组中真正有值的个数)
s[slen] = 'R';
int dis = -1, np = 0;
for( int i = 1; i < slen + 1; i++ ){
if( s[i] == 'R' ){
dis = max( dis, i - np );
np = i;
}
}
cout << dis << "\n";
}
return 0;
}
D - Pair of Topics
题意:给定长度为n的两个数组,计算 ai + aj > bi + bj( i < j )的 ( i,j )个数。
思路:(尺取法)很明显这道题要对上面的式子变形,令ci = ai - bi, 讲上面等式变形为 ci + cj > 0;然后排序,令l为左端点,r为右端点,如果c[r] + c[l] > 0,则[l+1,r]这个区间都与 r 满足关系,然后r–-,如果c[r] + c[l] < 0,都不满足关系,则l++。尺取法的时间复杂度为O(logn) 但是快排的复杂度为O(nlogn)。
(二分)令ci = ai - bi, 讲上面等式变形为 ci + cj > 0;满足这个式子,从前往后枚举ci,那么就无关i<j,将c数组升序排列,如果ci>0 则后面的全部满足,如果ci <= 0 则用二分找恰好大于|ci|的位置,这个位置以及后面的数都满足。时间复杂度为 O(n*logn)。
答案代码(取尺):
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
ll a[N];
int main(){
ios :: sync_with_stdio( false );
cin.tie( NULL );
ll n, num;
cin >> n;
for( ll i = 0; i < n; i++ ){
cin >> a[i];
}
for( ll i = 0; i < n; i++ ){
cin >> num;
a[i] -= num; //可节省空间
}
sort( a, a + n );
ll l = 0, r = n - 1, ans = 0;
while( l < r ){
if( a[l] + a[r] > 0 ){
ans += r - l; //如果满足那么 l + 1 与 r 满足;l + 2 与 r 满足……
--r;
}
else{
++l;
}
}
cout << ans;
return 0;
}
答案代码(二分):
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int c[maxn], a[maxn];
void solve(){
int n, b;
scanf("%d", &n);
for (int i = 0; i < n; ++i){
scanf("%d", &a[i]);
}
for (int i = 0; i < n; ++i){
scanf("%d", &b);
c[i] = a[i] - b;
}
sort(c, c + n);
ll ans = 0;
//极端情况,如果ci都大于0,用组合数来表示是maxn * (maxn - 1) / 2.这个数要超int
int i;
for (i = 0; i < n; ++i){
if (c[i] > 0){
break;
}
int pos = upper_bound(c, c + n, abs(c[i])) - c;
ans += n - pos;
}
//满足组合数,直接利用组合数计算即可。这里有个坑点就是需要注意数据类型溢出
ans += (ll)(n - i) * (n - i - 1) / 2;
printf("%lld\n", ans);
}
int main(){
solve();
return 0;
}