2020.5.3
题目链接:传送门
题目概述:查找1-n个不为零的数列中和和差相等的子序列个数
解题思路:这道题用暴力非常简单,但肯定超时,一直在找优化的办法。首先想到和和积相等,肯定是在考察数组中1和2的数量,之前用1和2分治卡过去了,今天上kattis看貌似已经不行。得另想办法,但是我想不到啊,分治好像也不行,没有优化空间。然后问了下群里西工大的大佬@I,给出关键思路,即当暴力的时候,如果 ai 大于1,则超过log2个不为1的数字之后和永远无法和积相等。妙啊,然后因为坑爹的2e6数据re了一波。然后AC。看来以后还是得多练一下思路。区域赛目前补出来9道了,还是得多加练习,争取今年去一趟nac。
特别鸣谢:凯哥
代码:
#include <bits/stdc++.h>
using namespace std;
#define limit (100000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-6
#define FASTIO ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%lld\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(int i = a ; i <= b ; ++i)
#define per(i, a, b) for(int i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define MOD 998244353
#define FOPEN freopen("C:\\Users\\administrator01\\CLionProjects\\untitled24\\data.txt", "rt", stdin)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
ll sign = 1, x = 0;char s = getchar();
while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
while(s >= '0' && s <= '9'){x = x * 10 + s - '0';s = getchar();}
return x * sign;
}//快读
void write(ll x){
if(x / 10) write(x / 10);
putchar(x % 10 + '0');
}
int n , m;
int vis[limit], f[limit];
void check(int x, int &ans){
int t = 1;
int len = n;
ll prod = f[x], sum = f[x];
int lim = log2(n - x + 1) + 1;
int s = 0;
for(int i = x + 1; t <= lim && s <= lim && i <= n ; ){
if(!vis[i]){
++t;
prod *= f[i];
sum += f[i];
if(prod == sum){
++ans;
//printf("At %d, %dth, prod %lld and sum %lld\n", x,i,prod, sum);
}
++i;
}else{
++s;
++sum;
if(prod >= sum && prod - sum < vis[i]){
//printf("At %d, %dth\n", x,i);
++ans;
}
sum += vis[i] - 1;
i += vis[i];
}
}
}
int main(){
#ifdef LOCAL
FOPEN;
//freopen("C:\\Users\\administrator01\\CLionProjects\\untitled24\\out.txt", "w", stdout);
#endif
n = read();
int flag = 0, iter = 0, num = 0;
int s1 = 0, s2 = 0;
rep(i ,1, n){
f[i] = read();
if(f[i] == 1){
if(flag){
vis[iter]++;
continue;
}
flag = 1;
iter = i;
vis[iter]++;
++num;
s1 = 1;
}
if(f[i] == 2){
s2++;
}
if(flag && f[i] != 1){
num = iter = flag = 0;//归零
}
}
rep(i ,1, n){
if(vis[i - 1])vis[i] = vis[i - 1] - 1;
}
int ans = 0;
for(int i = 1 ; i <= n ; ++i){
check(i,ans);
}
write(ans);
return 0;
}