20190823考试反思

  这次考试CE了。

  原因是我改了一个longlong没编译,然后最后查出来的时候已经没时间了。

  不CE的话应该rk7左右。update:因为这个CE把我卡出了第一基房!!!!

  但是都是暴力分。

  T1:是一个规律题,给了5个样例,但我都没看出来,也是废了。我用背包A了

  这个题首先是一道比较屎的背包都能想到。

  但是转移会出错,原因在于:$f[j]|=f[(j-w[i]+k)%k]$这个东西转移顺序出问题了。

  解决办法就是一个转移循环k次。

  复杂度$O(nk^{2})$但是题目给了三个分档,k=100,k=1000,n,k=100000

  首先100的肯定可以。

  1000的就会出问题。但是有一个剪枝就是每次转移的时候转移完看看答案是否变化,如果不变化那么很显然就不用在循环接下来的保证正确性的k次循环。经过实测在100次左右答案就不在变化,复杂度可过。

  100000的nk就死了,那么没办法,n的循环不能省,但是k的循环……,我可以随机找一个容积更新,大概随机次数在200次之后就稳定了。所以。。。。。n*?似乎可过????

  数据貌似卡不了我复杂度,正解$O(nlogn)$,n极限在1e5,然后内层循环能循环250。。,因为他即使是构造的,但我仍是随机看人品更新的

  然后多交两次就A了。

  其实正确率还是蛮高的,在控制使n*k<=25000000的时候接近100%

  n*k<=10000000的时候交3次WA1次。

  

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
using namespace std;
const int N=1000020;
int w[N],a[N],f[N],cnt;
long long rd()
{
    long long s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
int main()
{
    //freopen("math5.in","r",stdin);
    srand(unsigned(time(0)));
    int n=rd(),k=rd();
    for(int i=1;i<=n;i++) a[i]=rd();
    for(int i=1;i<=n;i++)
    {
        if(!f[a[i]%k])
        {
            f[a[i]%k]=1;
            w[++cnt]=a[i]%k;
        }
    }
    int ans=0;
    sort(w+1,w+cnt+1,greater<int>());
    if(n==1)
    {
        int gcd=a[1]%k;
        for(int i=1;i<=k;i++)
            f[1ll*gcd*i%k]=1;
        for(int i=0;i<k;i++)
            ans=ans+f[i];
        printf("%d\n",ans);
        for(int i=0;i<k;i++)
            if(f[i]) printf("%d ",i);
        puts("");
        return 0;
        return 0;
    }
    if(k<=100)
    {
        for(int i=1;i<=cnt;i++)
        {
            for(int p=1;p<=k;p++)
            {
                int sum=0;
                for(int j=0;j<k;j++)
                {
                    f[j]|=f[(j-w[i]+k)%k];
                    sum+=f[j];
                }
                if(ans==sum) break;
                ans=max(ans,sum);
            }
        }
        printf("%d\n",ans);
        for(int i=0;i<k;i++)
            if(f[i])printf("%d ",i);
        puts("");
        return 0;
    }
    else if(k<=1000)
    {
        for(int i=1;i<=cnt;i++)
        {
            for(int p=1;p<=k;p++)
            {
                int sum=0;
                for(int j=0;j<k;j++)
                {
                    f[j]|=f[(j-w[i]+k)%k];
                    sum+=f[j];
                }
                if(sum==ans) break;
                else ans=max(ans,sum);
            }
        }
        printf("%d\n",ans);
        for(int i=0;i<k;i++)
            if(f[i])printf("%d ",i);
        puts("");
        return 0;
    }
    else
    {
        for(register int i=1;i<=cnt;++i)
        {
            for(register int p=1;p*cnt<=25000000;++p)
            {
                const int j=rand()%k;
                f[j]|=f[(j-w[i]+k)%k];
            }
        }
        for(register int i=0;i<k;i++) ans+=f[i];
        printf("%d\n",ans);
        for(register int i=0;i<k;i++)
            if(f[i])printf("%d ",i);
        puts("");
        return 0;
    }
}
/*
g++ -std=c++11 1.cpp -o 1
./1
2 8
4 12
*/
View Code

 

  T2:我做这题头脑很屎。一开始打了$O(n^{3}m^{3})$的打法,只能过暴搜。

  然后硬是转成图论题topu强行降成$O(n^{2}m^{2})$以为A了。(事实上只是把DP之间问题和子问题的关系图建出来了)

  结果后来发现数据范围只能$O(nm)$可过。

  然后我就暴毙了,

  方程想复杂了。

  优化其实用4个树状数组维护拆开绝对值后的最大值就行了。

  但是发现不用树状数组决策不会更劣因为在求最大值。

  直接用变量。

  

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int N=4020;
int a[N][N],b[N][N],la[N*N],n,m,tt,cnt;
long long f[N][N],ans;
struct node{int x,y;};
struct bitar
{
    long long bin[N][N];
    void add(int x,int y,long long w)
    {
        for(register int i=x;i<=n;i+=(i&-i))
            for(register int j=y;j<=m;j+=(j&-j))
                bin[i][j]=max(bin[i][j],w);
    }
    long long ask(int x,int y)
    {
        long long sum=-0x7fffffff;
        for(register int i=x;i;i-=(i&-i))
            for(register int j=y;j;j-=(j&-j))
                sum=max(sum,bin[i][j]);
        return sum;
    }
}aw,dw,as,ds;
int rd()
{
    register int s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
int main()
{
    //freopen("biology4.in","r",stdin);
    n=rd(),m=rd();
    int mini=0x7fffffff;
    for(register int i=1;i<=n;i++)
        for(register int j=1;j<=m;j++)
        {
            a[i][j]=rd();
            if(a[i][j])    la[++tt]=a[i][j];
        }
    sort(la+1,la+tt+1);
    int len=unique(la+1,la+tt+1)-la-1;
    vector<node> p[len+2];
    for(register int i=1;i<=n;++i)
        for(register int j=1;j<=m;++j)
        {
            int tmp=lower_bound(la+1,la+len+1,a[i][j])-la;
            p[tmp].push_back((node){i,j});
            b[i][j]=rd();
        }
    long long ask1=0,ask2=0,ask3=0,ask4=0;
    for(int t=1;t<=len;t++)
    {
        for(int k=0;k<p[t].size();k++)
        {
            int i=p[t][k].x,j=p[t][k].y;
            if(t==1) f[i][j]=b[i][j];
            else f[i][j]=max(f[i][j],max(max(ask1+i+j,ask2+i-j),max(ask3-i+j,ask4-i-j))+b[i][j]);
        }
        for(int k=0;k<p[t].size();k++)
        {
            int i=p[t][k].x,j=p[t][k].y;
            ask1=max(ask1,f[i][j]-i-j);ask2=max(ask2,f[i][j]-i+j);
            ask3=max(ask3,f[i][j]+i-j);ask4=max(ask4,f[i][j]+i+j);
            ans=max(ans,f[i][j]);
        }
    }
    printf("%lld\n",ans);
}
/*
g++ 1.cpp -o 1
./1
3 3
1 2 3
4 5 6
7 8 9
7 8 9
7 6 4
2 10 8
*/
View Code

 

  T3:我又不会异或。。。。

  第一问直接用桶存位即可。

  第二问用一个可持久化trie树维护区间中异或a的值>b的个数。

  和数位DP一样记忆化搜索即可。

  

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod=1e9+7;
const int N=100020;
int a[N],f[N][25],mac[30],rt[N],tt,stack[N],top,lm[N],rm[N];
bool b[N],c[N];
struct trie{int l,r,s;}tr[N*25];
long long rd()
{
    long long s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9'){if(cc=='-') w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
void build(int x,int &k,int len)
{
    k=++tt;tr[k]=tr[x];
    if(len==0){tr[k].s++;return;}
    if(b[len]==0) build(tr[x].l,tr[k].l,len-1);
    else build(tr[x].r,tr[k].r,len-1);
    tr[k].s=tr[tr[k].l].s+tr[tr[k].r].s;
}
int dfs(int k,int len,int lim)
{
    if(!k) return 0;
    if(!lim) return tr[k].s;
    if(len==0) return lim^1;
    long long ans=0;
    if((b[len]^0)>=c[len])ans=(ans+dfs(tr[k].l,len-1,lim&&((b[len]^0)==c[len])))%mod;
    if((b[len]^1)>=c[len]) ans=(ans+dfs(tr[k].r,len-1,lim&&((b[len]^1)==c[len])))%mod;
    return ans;
}
int main()
{
    int n=rd(),opt=rd();long long ans1=0,ans2=0;mac[0]=1;
    for(int i=1;i<=25;i++) mac[i]=mac[i-1]<<1;
    for(int i=1;i<=n;i++) a[i]=rd();
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=22;j++) f[i][j]=f[i-1][j]+((a[i]&mac[j])!=0);
        for(int k=1,x=a[i];k<=22;k++,x>>=1) b[k]=(x&1);
        build(rt[i-1],rt[i],22);
    }
    a[0]=a[n+1]=0x7fffffff;
    for(int i=0;i<=n+1;i++)
    {
        while(top>0&&a[stack[top]]<a[i]) rm[stack[top]]=i,top--;
        stack[++top]=i;
    }top=0;
    for(int i=n+1;i>=0;i--)
    {
        while(top>0&&a[stack[top]]<=a[i]) lm[stack[top]]=i,top--;
        stack[++top]=i;
    }
    for(int i=1;i<=n;i++)
    {
        for(int k=1,x=a[i];k<=22;k++,x>>=1)c[k]=(x&1);
        if(i-lm[i]<rm[i]-i)
        {
            for(int j=lm[i]+1;j<=i;j++)
            {
                for(int k=1,x=a[j];k<=22;k++,x>>=1) b[k]=(x&1);
                    ans2=(ans2+1ll*a[i]*(dfs(rt[rm[i]-1],22,1)-dfs(rt[i-1],22,1)+mod)%mod)%mod;
                for(int k=0;k<=22;k++)
                {
                    if(a[j]&mac[k])ans1=(ans1+1ll*a[i]*mac[k]%mod*(rm[i]-i+mod-(f[rm[i]-1][k]-f[i-1][k]+mod)%mod+mod)%mod)%mod;
                    else ans1=(ans1+1ll*a[i]*mac[k]%mod*(f[rm[i]-1][k]-f[i-1][k]+mod)%mod)%mod;
                }
            }
        }
        else
        {
            for(int j=i;j<rm[i];j++)
            {
                for(int k=1,x=a[j];k<=22;k++,x>>=1) b[k]=(x&1);
                    ans2=(ans2+1ll*a[i]*(dfs(rt[i],22,1)-dfs(rt[lm[i]],22,1)+mod)%mod)%mod;
                for(int k=0;k<=22;k++)
                {
                    if(a[j]&mac[k])ans1=(ans1+1ll*a[i]*mac[k]%mod*(i-lm[i]+mod-(f[i][k]-f[lm[i]][k]+mod)%mod+mod)%mod)%mod;
                    else ans1=(ans1+1ll*a[i]*mac[k]%mod*(f[i][k]-f[lm[i]][k]+mod)%mod)%mod;
                }
            }
        }
    }
    if(opt==1) printf("%lld\n",ans1);
    if(opt==2) printf("%lld\n",ans2);
    if(opt==3) printf("%lld\n%lld\n",ans1,ans2);
    return 0;
}
/*
g++ -std=c++11 2.cpp -o 2
./2
*/
View Code

 

  

posted @ 2019-08-27 12:08  starsing  阅读(133)  评论(0编辑  收藏  举报