zoukankan      html  css  js  c++  java
  • 20171025校内训练

    我们用dp[i][0/1][0/1]表示还剩最后i道题没切,目前主动权在小Z/小G手上,小Z/小G获得的最大收益

    但好像不用记第3维,拿前缀和一减就算出来了(反正我打题的时候记了第3维)

    怎么dp呢?

    我们发现,当前小Z/小G有两种选择,

    1自己切这道题,把主动权给对方(假设此时主动权在小Z手上,即dp[i][0][0]=dp[i+1][1][0]+d[i])

    2让对方切这道题,主动权还在自己手上(假设此时主动权在小Z手上,即dp[i][0][0]=dp[i+1][0][0])

    显然,拥有主动权的人肯定会选这两种方案的最大值(假设此时主动权在小Z手上,即dp[i][0][0]=max(dp[i+1][1][0]+d[i],dp[i+1][0][0]),即另一个人(小G)为dp[i][0][1]=dp[i+1][1][1]或dp[i+1][0][1]+d[i](看掌握主动权的那个人选哪种)

    然后记搜一下就完了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    struct xxx{int a[2];}dp[50100][2];
    int b[50100],n;
    xxx DP(int T,int i)
    {
        if(T==n+1)
        {
            xxx xx;xx.a[0]=0;xx.a[1]=0;return xx;
        }
        if(dp[T][i].a[0]!=-1)return dp[T][i];
        xxx c=DP(T+1,i);xxx d=DP(T+1,i^1);
        if(c.a[i]>d.a[i]+b[T])
        dp[T][i].a[i]=c.a[i],dp[T][i].a[i^1]=c.a[i^1]+b[T];
        else
        dp[T][i].a[i]=d.a[i]+b[T],dp[T][i].a[i^1]=d.a[i^1];
    //    cout<<T<<" "<<i<<" "<<dp[T][i].a[0]<<" "<<dp[T][i].a[1]<<endl;
        return dp[T][i];
    }
    int main()
    {
        freopen("problem.in","r",stdin);freopen("problem.out","w",stdout);
        memset(dp,-1,sizeof(dp));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&b[i]);
        xxx aa=DP(1,0);
        cout<<aa.a[0]<<" "<<aa.a[1];
        return 0;
    }
    View Code

    一开始把题目看成长方形的了,想了老半天。。。

    先说一下题意,这道题题意有点难懂

    有一个正方形网格,2~n-1行的第1列和第n列,和2~n-1列的第1行和第n行可以发车,每辆车速度相等且只能一直横着走或一直竖着走,不能拐弯,且你发的车不能相撞(即不同的车不能在同一时刻到达同一格),有一些格子有障碍,且车也不能撞障碍,求最多能发几辆车

    样例

    我们发现,由于正方形是对称的,所以影响关系其实会形成一个环,即下图中绿色地点发车的车不会撞到不在绿色位置发车的车,但它们可能会互相撞到。

    即每个行i只会与行n-i+1,列i,列n-i+1有关

    显然,对于这8个发车地点,我们最多能选4个使得它们不相撞,即选蓝色的4个或绿色的4个都可以

    但是,如果有障碍在这两行两列上的话,则该行/列不能发车

    然后我们从2~n/2,看看最多能发几辆车,计算答案即可。

    若n是奇数,则第n/2+1行或n/2+1列上没有障碍,那么它对答案的贡献就是1,否则就是0

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int a[200100],b[200100];
    int main()
    {
        freopen("car.in","r",stdin);freopen("car.out","w",stdout);
        int n,m,ans=0;scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);a[x]=1;b[y]=1;}
        for(int i=2;i+i<=n;i++)
        {
            int j=n-i+1;
            ans+=4-a[i]-a[j]-b[i]-b[j];
        }
        if(n&1)ans+=1-(a[n/2+1]&b[n/2+1]);
        printf("%d",ans);
        return 0;
    }
    View Code

     

    首先,我们要认识gcd的几个性质:

    1、gcd没有逆运算(和max一样),即你不可能用gcd的结果来求出原数,这就导致了无法前缀和

    2、gcd(a,b)==gcd(c,b)(a==c),但是当a!=c时,gcd(a,b)也有可能等于gcd(c,b)。

    对于每个右端点,任取左端点,其对应的区间的gcd只有log种,从左向右推的同时维护每种gcd的左端点即可。

    如何维护左端点?

    我们用Gcd[i][0]表示第i种不同的gcd值,Gcd[i][1]表示该种值的最远的左端点(此时正在枚举右端点)

    由于我们新来了一个元素,所以我们把Gcd数组的每个元素与a[i]取个gcd,然后再把Gcd数组新加入一个元素:a[i]。(表示a[i]也是一种不同的gcd值)但是有可能a[i]会与前面重复呢?没关系,我们待会还要去重。

    那么这些Gcd有可能会相等,但是这里一定包含了以i为右端点,任取左端点的区间的所有不同种类的Gcd值(根据性质2)

    然后去重,每种相同元素保留最远的左端点,统计答案。

    时间复杂度O(n(logai)^2),由于这是最坏复杂度,实际上时间复杂度远远小于这个上界,所以能过。

    ans记得要看long long

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[500100],Gcd[100][2],tot=0,ggcd[100][2];
    int gcd(int a,int b)
    {
        if(b==0)return a;
        return gcd(b,a%b);
    }
    int main()
    {
        freopen("study.in","r",stdin);freopen("study.out","w",stdout);
        int n;scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        long long ans=-1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=tot;j++)Gcd[j][0]=gcd(Gcd[j][0],a[i]);
            Gcd[++tot][0]=a[i];Gcd[tot][1]=i;int tot2=0;
            for(int j=1;j<=tot;j++)
                if(Gcd[j][0]!=ggcd[tot2][0])
                {
                    ggcd[++tot2][0]=Gcd[j][0];ggcd[tot2][1]=Gcd[j][1];
                }
            tot=tot2;
            for(int j=1;j<=tot2;j++)
            {
                Gcd[j][0]=ggcd[j][0];Gcd[j][1]=ggcd[j][1];
                ans=max(ans,(long long)Gcd[j][0]*(long long)(i-Gcd[j][1]+1));
            }
        }
        cout<<ans;
        return 0;
     } 
    View Code
  • 相关阅读:
    BZOJ 2034 【2009国家集训队】 最大收益
    vijos P1780 【NOIP2012】 开车旅行
    BZOJ 2115 【WC2011】 Xor
    BZOJ 3631 【JLOI2014】 松鼠的新家
    BZOJ 4717 改装
    BZOJ 2957 楼房重建
    BZOJ 4034 【HAOI2015】 T2
    BZOJ 1834 【ZJOI2010】 network 网络扩容
    BZOJ 2440 【中山市选2011】 完全平方数
    BZOJ 2733 【HNOI2012】 永无乡
  • 原文地址:https://www.cnblogs.com/lher/p/7732323.html
Copyright © 2011-2022 走看看