继续存档

早上来补了一下昨天的题,不过肯定这两天的没法完全补起来

T1:

经典思路:关于位运算的题讨论每一位的贡献

#include<iostream>
#include<cstdio>
using namespace std;
int t,mod=1e9+7;;
long long l,r,all,cnt,ans;
long long count(long long x,int k){
    long long num=0;
    num+=x/(1ll<<(k+1));
    x-=(1ll<<(k+1))*num;
    num*=(1ll<<k);
    num+=((x>=(1ll<<k))?(x+1-(1ll<<k)):0);
    return num;
}
int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&l,&r);
        all=r-l+1;
        ans=0;
        for(int i=0;i<=31;i++){
            cnt=count(r,i)-count(l-1,i);
            ans=(ans+cnt*(all-cnt)%mod*(1ll<<(i+1))%mod)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

T2:

优化DP刷表可以卡过去,并不是完全的正解啦:P

(我才知道bool是1bit而int是4bits…一直以来bool都用int代替的…)

关键点:必败状态不能互相转移、打表+分析发现对于每个让二元组(x,y)必败的z,x、y所占用的数字不重复且x与y的差不重复。

题解里好像有点小锅,如果存在f(x,y)=k<i,则f(x+i-k,y)、f(x,y+i-k)、f(x+i-k,y+i-k)不可能等于i。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int t,x,y,z,maxn;
bool f[301][301][301];
int main()
{
    for(int i=0;i<=300;i++){
        for(int j=0;j<=300;j++){
            for(int k=0;k<=300;k++){
                if(!f[i][j][k]){
                    for(int x=1;x<=7;x++){
                        maxn=300;
                        if(x&1)maxn=min(maxn,300-i);
                        if(x&2)maxn=min(maxn,300-j);
                        if(x&4)maxn=min(maxn,300-k);
                        for(int l=1;l<=maxn;l++)f[i+(x&1)*l][j+((x>>1)&1)*l][k+((x>>2)&1)*l]=1;
                    }
                }
            }
        }
    }
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&x,&y,&z);
        if(f[x][y][z])printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
View Code

T3:

关键点在于转化题目。也是一个经典的思路:遇到绝对值的问题,可以考虑把绝对值拆成正负两种作差方法分开考虑。

于是对于一些si,它会被加两次或者减两次。对于另一些si,它会加一次减一次正好抵消。首位特殊讨论。

设计dp,首先可以想到+2、-2、0这三种。但是考虑2和-2的产生就会发现2和-2肯定是间隔的XD!所以还要考虑它们的间隔状态是否合法。

通过把0的状态拆成2->-2、-2->2两种来保证转移合法。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,k;
int f[30010][210][4],a[30010];
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    memset(f,-0x3f,sizeof(f));
    for(int i=0;i<=n;i++){
        for(int j=0;j<=3;j++){
            f[i][0][j]=0;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=min(i,k);j++){
            f[i][j][0]=max(f[i-1][j-1][3],f[i-1][j][0])+((j==1||j==k)?1:2)*a[i];
            f[i][j][2]=max(f[i-1][j-1][1],f[i-1][j][2])-((j==1||j==k)?1:2)*a[i];
            f[i][j][1]=max(f[i][j][0],f[i-1][j][1]);
            if(j!=1&&j!=k)f[i][j][1]=max(f[i][j][1],f[i-1][j-1][1]);
            f[i][j][3]=max(f[i][j][2],f[i-1][j][3]);
            if(j!=1&&j!=k)f[i][j][3]=max(f[i][j][3],f[i-1][j-1][3]);
        }
    }
    printf("%d\n",max(f[n][k][1],f[n][k][3]));
    return 0;
}
View Code

在尝试补这套题的时候发生了各种各样脑残的错误,例如“咦bool原来是1bit吗”之类的:D

脑子是个好东西 希望我有XDDDDDDDD

01-31 17:22