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

77 篇文章 0 订阅
65 篇文章 0 订阅

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 (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(1n10^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[n]=INF;//刚开始没有初始化a[n],导致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_2d2的等差数列能延续到多长,记作l_i,r_ili,ri

如果d_1\neq d_2
d​    1d2​,
那么枚举中间位置,答案为l_i*r_iliri

如果d_1=d_2d​    1=d2,枚举开始位置,答案为r_iri



#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[N],l[N],r[N];
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);
	}
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值