2018.8.21提升AB組模擬考試

爲何沒有8.20的考試?由於博主太蒟蒻不會NTT或是FFT。ios

 

T1 題意簡述:jzoj5838數組

 

Description

GZOI隊員們到X鎮遊玩。X鎮是一個很特別的城鎮,它有m+1條東西方向和n+1條南北方向的道路,劃分紅m*n個區域,這些區域標從北到南、從西到東的座標標識爲從座標 (1,1) 到座標(m,n)。 GZOI隊員們預先對這m*n個區域打分V(i,j)(分數可正可負)。分數越高表示他們越想到那個地方,越低表示他們越不想去。爲了方便遊玩,隊員們須要選定一個連續的區域集合做爲活動範圍。例如,若是他們選擇了最西北的區域(m1,nl)和最東南(m2,n2)區域(m1<=m2,n1<=n2),那他們的活動範圍是 {D(i,j)|m1<=i<=m2,n1<=j<=n2},其遊覽總分則爲這些活動範圍的區域總分。 GZOI隊員們但願他們活動範圍內的區域的分值總和最大。你的任務是編寫一個程序,求出他們的活動範圍(m1,nl),(m2,n2〉。 

Input

輸入第一行爲整數m(1<=m<=200),n(1<=n<=200),用空格隔開 下面爲m行,每行有n列整數,其中第i行第j列的整數,表明V(i,j),每一個整數之間用空格隔開,每一個整數的範圍是 [-200000,200000],輸入數據保證這些整數中,至少存在一個正整數。

Output

輸出只有一行,爲最高的分值。

 

   解題思路:求最大子矩陣。測試

             每一列的元素求前綴和後求最大子段和便可。優化

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll n,m,ans,a[201][201],sum[201][201],dp[201],mns[201];
ll sol()
{
    ll tmp=0;
    memset(dp,0,sizeof(dp));
    for(ll i=1;i<=m;i++)
        dp[i]=max(dp[i-1]+mns[i],mns[i]),tmp=max(tmp,dp[i]);
    return tmp;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++)
            scanf("%lld",&a[i][j]);
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++)
            sum[i][j]=sum[i-1][j]+a[i][j];
    for(ll i=1;i<=n;i++)
        for(ll j=i;j<=n;j++)
        {
            for(ll k=1;k<=m;k++)
                mns[k]=sum[j][k]-sum[i-1][k];
            ans=max(ans,sol());
        }
    printf("%lld\n",ans);
    return 0;
}

 


 

T2 題意簡述:jzoj4737spa

 

Description

Input

Output

Data Constraint

 

   解題思路:二分答案。.net

             橫縱座標分開計算。輸入時記錄下物體輸入順序。code

             把物體按座標排序,而後按照i*a[i]-sum[i-1]統計距離。blog

             發現這樣是O(nlog^2(n)),無法過所有測試點。排序

             出題人提供了一個特鬼畜的方法:ip

             在二分答案前先把物體按座標排序,記錄下座標排名。

             二分答案時按照排名直接O(n)排序。此法叫作小學生排序(真的有這個排序)。

             咳咳咳...作的時候才發現出題人的方法好像會T...吸氧才能過...

             GZZ大佬提供了一個4個樹狀數組的方法。因爲博主太懶因此沒改。

#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstring> 
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll n,m,ans,xar[600001],yar[600001],xno[600001],yno[600001],hlp[600001];
bool cmpx(ll x,ll y)
{
    return xar[x]<xar[y];
}
bool cmpy(ll x,ll y)
{
    return yar[x]<yar[y];
}
ll chk(ll x)
{
    ll tmp=0,cnt=0;
    memset(hlp,0,sizeof(hlp));
    for(ll i=1;i<=x;i++) tmp+=(x-1)*(xar[i]+yar[i]);
    for(ll i=1;i<=x;i++) hlp[xno[i]]=i;
    for(ll i=1;i<=n;i++)
        if(hlp[i]) cnt++,tmp-=2*xar[hlp[i]]*(x-cnt);
    cnt=0,memset(hlp,0,sizeof(hlp));
    for(ll i=1;i<=x;i++) hlp[yno[i]]=i;
    for(ll i=1;i<=n;i++)
        if(hlp[i]) cnt++,tmp-=2*yar[hlp[i]]*(x-cnt);
    return (tmp>m);
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld%lld",&xar[i],&yar[i]);
        xno[i]=i,yno[i]=i;
    }
    sort(xno+1,xno+1+n,cmpx);
    sort(yno+1,yno+1+n,cmpy);
    for(ll i=1;i<=n;i++) hlp[xno[i]]=i;
    memcpy(xno,hlp,sizeof(hlp));
    for(ll i=1;i<=n;i++) hlp[yno[i]]=i;
    memcpy(yno,hlp,sizeof(hlp));
    ll l=1,r=n;
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(chk(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    if(l>n) printf("-1\n");
    else printf("%lld\n",ans);
    return 0;
}

 


 

T3 題意簡述:jzoj4738

 

Description

Input

Output

Data Constraint

 

   解題思路:dp。

             設dp[i]表示枚舉到第i我的的總方案數,sum[i]表示前i我的中0的個數-1的個數。

             轉移方程爲dp[i]+=dp[j] (abs(sum[i]-sum[j])<=k)

             O(n^2)過不了,能夠用樹狀數組或線段樹優化。這裏介紹線段樹作法。

             每次轉移時統計[sum[i]-k,sum[i]+k]的方案數,而後把dp[i]加到線段樹的sum[i]處。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
#define MOD 1000000007
using namespace std;
ll n,k,a[100001],sum[100001],dp[100001];
ll tree[800001];
void revise(ll now,ll l,ll r,ll pos,ll num)
{
    if(l==r) {(tree[now]+=num)%=MOD;return;}
    ll mid=(l+r)>>1;
    if(pos<=mid) revise(now<<1,l,mid,pos,num);
    else revise(now<<1|1,mid+1,r,pos,num);
    tree[now]=tree[now<<1]+tree[now<<1|1];
}
ll query(ll now,ll l,ll r,ll L,ll R)
{
    if(L<=l&&r<=R)    return tree[now]%MOD;
    ll mid=(l+r)>>1;
    if(R<=mid) return query(now<<1,l,mid,L,R)%MOD;
    else if(L>mid) return query(now<<1|1,mid+1,r,L,R)%MOD;
    else return (query(now<<1,l,mid,L,R)%MOD+query(now<<1|1,mid+1,r,L,R)%MOD)%MOD;
}
int main()
{
    scanf("%lld%lld",&n,&k);
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1];
        if(!a[i]) sum[i]++;
        else sum[i]--;
    }
    dp[0]=1;
    revise(1,0,n<<1,n,1);
    for(ll i=1;i<=n;i++)
    {
        dp[i]=query(1,0,n<<1,max(sum[i]+n-k,0ll),min(sum[i]+n+k,n<<1));
        revise(1,0,n<<1,sum[i]+n,dp[i]);
    }
//    for(ll i=1;i<=n;i++)
//        for(ll j=0;j<i;j++)
//            if(abs(sum[i]-sum[j])<=k) (dp[i]+=dp[j])%=MOD;
    printf("%lld\n",dp[n]%MOD);
    return 0;
}
相關文章
相關標籤/搜索