HDU 5400 Arithmetic Sequence(数学,容斥)

来源:互联网 发布:cad可以画网络拓扑图吗 编辑:程序博客网 时间:2024/05/16 16:59

题目:

Arithmetic Sequence

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 938    Accepted Submission(s): 412


Problem Description
A sequence b1,b2,,bn are called (d1,d2)-arithmetic sequence if and only if there exist i(1in) such that for every j(1j<i),bj+1=bj+d1 and for every j(ij<n),bj+1=bj+d2.

Teacher Mai has a sequence a1,a2,,an. He wants to know how many intervals [l,r](1lrn) there are that al,al+1,,ar are (d1,d2)-arithmetic sequence.
 

Input
There are multiple test cases.

For each test case, the first line contains three numbers n,d1,d2(1n105,|d1|,|d2|1000), the next line contains n integers a1,a2,,an(|ai|109).
 

Output
For each test case, print the answer.
 

Sample Input
5 2 -20 2 0 -2 05 2 32 3 3 3 3
 

Sample Output
125
 

Author
xudyh
 

Source
2015 Multi-University Training Contest 9


题意:给一个数列,问这个数列中有多少个子数列,可以被分为两个序列,这两个序列都为等差数列(公差分别为d1和d2)。


思路:枚举每个数字,求出它的左边能构成的公差为d1的等差数列的左边界l和它的右边能构成的公差为d2的等差数列的右边界r,那么对于这个【l,r】区间内的每个子区间都满足题意,共有(r-l+1)*(r-l+2)/2个子区间。但是这样可能会重复计算,因为枚举不同数字的时候可能会得到相同区间,由于区间的左边界是非降的,我们只需要记录已经出现过的右边界的最大值,就能得到当前区间和出现过的区间重叠的地方,减去这部分区间就可以了。


代码:

#include <cstdlib>#include <cctype>#include <cstring>#include <cstdio>#include <cmath>#include<climits>#include <algorithm>#include <vector>#include <string>#include <iostream>#include <sstream>#include <map>#include <set>#include <queue>#include <stack>#include <fstream>#include <numeric>#include <iomanip>#include <bitset>#include <list>#include <stdexcept>#include <functional>#include <utility>#include <ctime>using namespace std;#define PB push_back#define MP make_pair#define REP(i,x,n) for(int i=x;i<(n);++i)#define FOR(i,l,h) for(int i=(l);i<=(h);++i)#define FORD(i,h,l) for(int i=(h);i>=(l);--i)#define SZ(X) ((int)(X).size())#define ALL(X) (X).begin(), (X).end()#define RI(X) scanf("%d", &(X))#define RII(X, Y) scanf("%d%d", &(X), &(Y))#define RIII(X, Y, Z) scanf("%d%d%d", &(X), &(Y), &(Z))#define DRI(X) int (X); scanf("%d", &X)#define DRII(X, Y) int X, Y; scanf("%d%d", &X, &Y)#define DRIII(X, Y, Z) int X, Y, Z; scanf("%d%d%d", &X, &Y, &Z)#define OI(X) printf("%d",X);#define RS(X) scanf("%s", (X))#define MS0(X) memset((X), 0, sizeof((X)))#define MS1(X) memset((X), -1, sizeof((X)))#define LEN(X) strlen(X)#define F first#define S second#define Swap(a, b) (a ^= b, b ^= a, a ^= b)#define Dpoint  strcut node{int x,y}#define cmpd int cmp(const int &a,const int &b){return a>b;} /*#ifdef HOME    freopen("in.txt","r",stdin);    #endif*/const int MOD = 1e9+7;typedef vector<int> VI;typedef vector<string> VS;typedef vector<double> VD;typedef long long LL;typedef pair<int,int> PII;//#define HOMEint Scan(){int res = 0, ch, flag = 0;if((ch = getchar()) == '-')//判断正负flag = 1;else if(ch >= '0' && ch <= '9')//得到完整的数res = ch - '0';while((ch = getchar()) >= '0' && ch <= '9' )res = res * 10 + ch - '0';return flag ? -res : res;}/*----------------PLEASE-----DO-----NOT-----HACK-----ME--------------------*/#define MAXN 100000int a[MAXN+5];int l[MAXN+5];int r[MAXN+5];//int len1[MAXN+5];//int len2[MAXN+5];int main(){int n,d1,d2;while(RIII(n,d1,d2)!=EOF){    REP(i,0,n)    scanf("%d",&a[i]);    //len1[0]=0;    l[0]=0;    for(int i=1;i<n;i++)        if(a[i]==a[i-1]+d1)        l[i]=l[i-1];       else        l[i]=i;        r[n-1]=n-1;    for(int i=n-2;i>=0;i--)        if(a[i]==a[i+1]-d2)        r[i]=r[i+1];        else        r[i]=i;    long long int ans=0;    int last=-1;    for(int i=0;i<n;i++)        {            long long int c=r[i]-l[i]+1;            ans+=c*(c+1)/2;            c=min(last,r[i])-l[i]+1;            if(c>0)                ans-=c*(c+1)/2;            last=max(last,r[i]);        }    printf("%I64d\n",ans);}        return 0;}


0 0
原创粉丝点击