您的位置:首页 > 产品设计 > UI/UE

HDU-5400 Arithmetic Sequence(数学 || DP)

2015-08-18 18:51 477 查看


Arithmetic Sequence

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)



Problem Description

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

Teacher Mai has a sequence a1,a2,⋯,an.
He wants to know how many intervals [l,r](1≤l≤r≤n) 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(1≤n≤10^5,|d1|,|d2|≤1000),
the next line contains n integers a1,a2,⋯,an(|ai|≤10^9).

Output

For each test case, print the answer.

Sample Input

5 2 -2
0 2 0 -2 0
5 2 3
2 3 3 3 3


Sample Output

12
5


法一:

和队友讨论之后,觉得每一个序列,只要其符合(①公差为d1②公差为d2③前面公差为d1,后面公差为d2)三者任意一个就满足题意

然后求出每一个最长的符合题目条件的序列,然后求其连续子序列(元素个数>=2)

假设一个最长的符合题目条件的序列的元素个数为tmp,则其连续子序列中:元素个数为tmp个的有1个,元素个数为tmp-1个的有2个……以此类推,将所有连续子序列(元素个数>=2)加起来得:((tmp-1)*tmp)/2

不能通过最长的符合题目条件的序列算出元素个数为1的子序列个数:①某一个元素单独构成一个序列(我用的方法不计入其中)②前一个最长的符合题目条件的序列的最后一个元素是下一个最长的符合题目条件的序列的第一个元素(主要原因)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int INF=0x3f3f3f3f;
const int MAXN=100005;

int n,a[MAXN];

int main() {
int i,j,d1,d2;
long long ans,tmp;//long long 才能过
while(3==scanf("%d%d%d",&n,&d1,&d2)) {
for(i=0;i<n;++i)
scanf("%d",a+i);
ans=n;
a
=INF;//刚开始没有初始化a
,导致WA两次。。。
for(i=0;i<n;) {
if(a[i+1]==a[i]+d1) {
j=i+1;
while(j<n&&a[j+1]==a[j]+d1)
++j;
while(j<n&&a[j+1]==a[j]+d2)
++j;
tmp=j-i+1;
ans+=((tmp*(tmp-1))>>1);//答案加上每个最长符合条件的序列的连续子序列(元素个数>=2)的个数
i=j;
}
else if(a[i+1]==a[i]+d2) {
j=i+1;
while(j<n&&a[j+1]==a[j]+d2)
++j;
tmp=j-i+1;
ans+=((tmp*(tmp-1))>>1);//同上
i=j;
}
else
++i;
}
printf("%I64d\n",ans);
}
return 0;
}


法二:

另一个队的大神想到了DP的解法(果然DP最简单)

#include <iostream>
#include <stdio.h>

using namespace std;

long long a[100500];
long long f[100500][2];
long long ans;

int main()
{
int n,d1,d2,i;
while(cin >> n >> d1 >> d2){
for(i = 0; i < n; i ++)
scanf("%I64d",&a[i]);
ans = 1;
f[0][0] = 1;
f[0][1] = 0;
for(i = 1; i < n; i ++){
if(a[i] - a[i-1] == d1){
f[i][0] = f[i-1][0] + 1;
}
else{
f[i][0] = 1;
}
if(a[i] - a[i-1] == d2 && d1 != d2){
f[i][1] = f[i-1][0] +  f[i-1][1];
}
else{
f[i][1] = 0;
}
ans += f[i][0];
ans += f[i][1];
}
printf("%I64d\n",ans);
}
return 0;
}


法三:

官方给出的解法:

首先预处理出来出ii这个位置向前d_1d​
1的等差序列和向后d_2d​2​​的等差数列能延续到多长,记作l_i,r_il​i​​,r​i​​。

如果d_1\neq
d_2

​​d​
1≠d​2​​,那么枚举中间位置,答案为l_i*r_il​i​​∗r​i​​。

如果d_1=d_2d​
1=d​2​​,枚举开始位置,答案为r_ir​i​​。

#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#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>
#include <cassert>
#include <complex>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define ACCU accumulate
#define TWO(x) (1<<(x))
#define TWOL(x) (1ll<<(x))
#define clr(a) memset(a,0,sizeof(a))
#define POSIN(x,y) (0<=(x)&&(x)<n&&0<=(y)&&(y)<m)
#define PRINTC(x) cout<<"Case #"<<++__<<": "<<x<<endl
#define POP(x) (__builtin_popcount(x))
#define POPL(x) (__builtin_popcountll(x))
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef long long ll;
typedef long double LD;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef vector<ll> VL;
typedef vector<PII> VPII;
typedef complex<double> CD;
const int inf=0x20202020;
const ll mod=1000000007;
const double eps=1e-9;
const double pi=3.1415926535897932384626;
const int DX[]={1,0,-1,0},DY[]={0,1,0,-1};
ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll powmod(ll a,ll b,ll mod) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
// head

const int N=101000;
int n,d1,d2,a
,l
,r
;
ll ans;
int main() {
while (scanf("%d%d%d",&n,&d1,&d2)!=EOF) {
rep(i,0,n) scanf("%d",a+i);
rep(i,0,n) if (i==0||a[i-1]+d1!=a[i]) l[i]=1; else l[i]=l[i-1]+1;
per(i,0,n) if (i==n-1||a[i]+d2!=a[i+1]) r[i]=1; else r[i]=r[i+1]+1;
ans=0;
rep(i,0,n) if (d1!=d2) ans+=(ll)l[i]*r[i]; else ans+=r[i];
printf("%lld\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: