2016"百度之星" - 初赛(Astar Round2B)

1001 区间的价值:

   RMQ+扫描法

  我们预处理RMQ求任意区间的最大值

  预处理出以a[i]为最小值 能向左延伸 向右延伸的 L[i], R[i]

  那么对于 一个答案 (L[i], R[i]) *rmq(L[i],R[i]) 为此长度的答案,我们可以发现他是可以更新到小于其长度的所有长度答案的,更新就好

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include<map>
using namespace std;
const int N = 1e5+10, M = 30005, mod = 1e9 + 7, inf = 0x3f3f3f3f;
typedef long long ll;
ll a[N],dp[N][30],ans[N],las[N];
int l[N],r[N],n;
void RMQ_init() {
    memset(dp,0,sizeof(dp));
    memset(l,0,sizeof(l));
    memset(r,0,sizeof(r));
    for(int i=1;i<=n;i++) dp[i][0] = a[i];
    for(int j=1;(1<<j)<=n;j++) {
        for(int i=1;i + (1<<j) - 1 <= n; i++) {
            if(dp[i][j-1] > dp[i+(1<<(j-1))][j-1])
                dp[i][j] =  dp[i][j-1];
            else {
                 dp[i][j] =  dp[i+(1<<(j-1))][j-1];
            }
        }
    }
     l[1] = 1;a[0] = -1000;a[n+1] = -10000;
    for(int i=2;i<=n;i++) {
        int tmp = i-1;
        while(a[i]<=a[tmp]) tmp = l[tmp]-1;
        l[i] = tmp+1;
    }
    r[n] = n;
    for(int i=n-1;i>=1;i--) {
         int tmp = i+1;
        while(a[i]<=a[tmp]) tmp = r[tmp] + 1;
        r[i] = tmp - 1;
    }
}
ll rmq(int l,int r) {
    if(l==r) return a[l];
    int k = (int) (log((double) r-l+1) / log(2.0));
    return max(dp[l][k], dp[r - (1<<k) + 1][k]);
}
int main() {
    while(scanf("%d",&n)!=EOF) {
        for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
        RMQ_init();
        for(int i=1;i<=n;i++) ans[i] = -1;
        for(int i=1;i<=n;i++) {
            ll mm = rmq(l[i],r[i]);
            ans[r[i]-l[i]+1] = max(mm*a[i],ans[r[i]-l[i]+1]);
        }
        las[n+1] = -1;
        for(int i=n;i>=1;i--) {
            las[i] = max(ans[i],las[i+1]);
        }
        for(int i=1;i<=n;i++) printf("%I64d\n",las[i]);
    }
    return 0;
}
View Code

1003 瞬间移动:

  组合数学

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<stack>
#include<map>
#define ll __int64
#define mod 1000000007
using namespace std;
ll poww(ll a,ll n)
{
   ll r=1,p=a;
   while(n)
   {
       if(n&1) r=(r*p)%mod;
       n>>=1;
       p=(p*p)%mod;
   }
   return r;
}
ll coun(ll n,ll m) 
{
    ll sum=1; 
    for(ll i=1,j=n;i<=m;i++,j--)
    {
        sum*=j;
        sum%=mod;
        sum*=poww(i,1000000005);
        sum%=mod;
    }
    return sum;
}
 ll x,y,z,t; 
 ll n,k;
 ll ans;
int main()
{
    while(scanf("%I64d %I64d",&x,&y)!=EOF)
    {
        ans=0;
        n=(x+y)-4;
        k=x-2;
        ans=coun(n,k);
        cout<<ans<<endl;
    }
    return 0;
}
View Code

1006 中位数计数

  我也不知道分类

  枚举以a[i]为中位数, 重构一个数组,小于a[i]的是-1,大于a[i]的是1,等于a[i]是0;,

  这个问题就变成了求这个数组有多少个区间包含0,且区间和是0的个数,这个用前缀解决

  map超时

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include<queue>
#include<map>
using namespace std;
const int N = 1e5+20, M = 1e4, mod = 1000000007,inf = 1e9;
typedef long long ll;

int a[N],b[N],n,now[N];
int H[N];
ll ans[N];
int  f[N],h[N];

int main() {
    while(scanf("%d",&n)!=EOF) {
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i] = a[i];
        for(int i=1;i<=n;i+=1) {

            memset(f,0,sizeof(f));
            memset(h,0,sizeof(h));

            for(int j=1;j<=n;j++)
            if(a[i]==a[j]) now[j] = 0;
            else if(a[i]>a[j]) now[j] = 1;
            else if(a[i]<a[j]) now[j] = -1;

           int last = 0,mx = 0;
           ll aa = 1;
            for(int j=i-1;j>=1;j--) f[last+now[j]+M]++,last +=now[j],mx = max(mx,last);
            last = 0;
            for(int j=i+1;j<=n;j++) h[last+now[j]+M]++,last +=now[j],mx = max(mx,last);
            for(int j=1;j<=mx;j++) aa += ((ll)f[j+M]*(ll)h[-j+M]),aa+=((ll)f[-j+M]*(ll)h[j+M]);
            aa+=f[0+M];
            aa+=h[0+M];
            aa+=(ll)f[0+M]*(ll)h[0+M];
            ans[i] = aa;
        }
        for(int i=1;i<n;i+=1) {
            printf("%I64d ",ans[i]);
        }
        printf("%I64d\n",ans[n]);
    }
    return 0;
}
View Code

 

posted @ 2016-05-22 16:48  meekyan  阅读(1267)  评论(4编辑  收藏  举报