维护一个新数组的末尾位置变量pos,遍历的时候不断更新即可。
#include <iostream> #include <vector> #include <algorithm> #include <cstring> #include <map> #include <set> #define mod 1000000007 //#define mod 998244353 #define ll long long #define pb push_back using namespace std; ll fpow(ll a, ll b) { ll ans = 1; for(; b; b >>= 1) { if(b & 1) ans = ans * a % mod; a = a * a % mod; } return ans; } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } int a[105], n; int main() { int T = 1; cin >> T; while(T--) { cin >> n; for(int i = 1; i <= n; i++) { cin >> a[i]; } ll ans = 0; a[0] = 0; int pos = 1; for(int i = 1; i <= n; i++) { if(a[i] > pos) { ans += a[i] - pos; pos += a[i] - pos; } pos++; } cout << ans << endl; } return 0; }
注意到长度为1的序列也满足单调递增的条件(虽然比较特殊),所以如果n为偶数一定可以(把序列分为n个子数组,每个子数组的最长单调递增子列长度为1,且一共有偶数个);如果n为奇数的话,只要整个序列不是单调递增的话一定可以(把a[i] >= a[i + 1]的这两个数拿出来,其最长递增子序列长度为1,剩下的n - 2个数自己构成一个子数组,这样保证xor和为0),否则不可(因为每个子数组的LCS就是本身,整个序列一定要被划分为若干对,n为奇数显然不可能划分为若干“对”)
#include <iostream> #include <vector> #include <algorithm> #include <cstring> #include <map> #include <set> #define mod 1000000007 //#define mod 998244353 #define ll long long #define pb push_back using namespace std; ll fpow(ll a, ll b) { ll ans = 1; for(; b; b >>= 1) { if(b & 1) ans = ans * a % mod; a = a * a % mod; } return ans; } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } ll n, a[100005]; int main() { int T = 1; cin >> T; while(T--) { cin >> n; for(int i = 1; i <= n; i++) { cin >> a[i]; } if(n % 2 == 0) puts("YES"); else { bool ok = 0; for(int i = 2; i <= n; i++) { if(a[i] <= a[i - 1]) { ok = 1; break; } } if(ok) puts("YES"); else puts("NO"); } } return 0; }
这个题其实可以暴力,对于每个数的位置pos直接判断2到pos+1有没有满足条件的位置(因为随着数列的变化,一个数的位置一定是单调不增的),如果没有则输出NO。所有数都可以则输出YES。
那么为什么能暴力呢?因为如果2到pos+1所有位置都不满足条件(即a[i]都是它们的倍数),如果考虑2到pos+1所有的素数,a[i]一定是这些素数若干次幂的乘积(唯一分解定理),而1到100所有的素数的乘积就已经爆int了,所以内循环根本跑不到100,故暴力可行。
#include <iostream> #include <vector> #include <algorithm> #include <cstring> #include <map> #include <set> #define mod 1000000007 //#define mod 998244353 #define ll long long #define pb push_back using namespace std; ll fpow(ll a, ll b) { ll ans = 1; for(; b; b >>= 1) { if(b & 1) ans = ans * a % mod; a = a * a % mod; } return ans; } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } ll n, a[100005]; int main() { int T = 1; cin >> T; while(T--) { cin >> n; for(int i = 1; i <= n; i++) { cin >> a[i]; } //最后一定是一个奇数 bool ok = 1; for(int i = 1; i <= n; i++) { bool flag = 0; for(int j = 2; j < i + 2; j++) { if(a[i] % j != 0) { flag = 1; break; } } if(!flag) { cout << "NO" << endl; ok = 0; break; } } if(ok) cout << "YES" << endl; } return 0; }
实际上是分类讨论的构造题,具体怎么构造见代码。对于最后一种情况画一下数轴就比较好理解了。
#include <iostream> #include <vector> #include <algorithm> #include <cstring> #include <map> #include <set> #define mod 1000000007 //#define mod 998244353 #define ll long long #define pb push_back using namespace std; ll fpow(ll a, ll b) { ll ans = 1; for(; b; b >>= 1) { if(b & 1) ans = ans * a % mod; a = a * a % mod; } return ans; } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } int a[105], n; int main() { int T = 1; cin >> T; while(T--) { ll x, y; cin >> x >> y; if(x == y) { cout << x << endl; continue; } if(x > y) { cout << x + y << endl; } else { if(y % x == 0) { cout << x << endl; } else { ll n = (x + y) / 2; if(n % x == y % n) { cout << n << endl; } else { n = y - (y % x) / 2; cout << n << endl; } } } } return 0; }