20171009模拟赛总结

来源:互联网 发布:大脚插件for mac 编辑:程序博客网 时间:2024/06/11 13:58

来源:不知道
分数:100+75+60
rank:10


T1 异或值

题意:

给定一个长度为n的序列,然后现在要在中间取出一个区间,求最大值^次大值的最大值
n<=2*10^6

分析:

一开始完全在分析异或有什么特点可以用在最大值次大值上的…一开始的想法是Trie树不过越往下想觉得第一题怎么可能那么麻烦。
然后就来看区间内最大值和次大值有什么特点了。
其实关于这类问题做得应该不算少了。大概有两种方法。

分治

solve(l,r)表示解决区间[l,r]内最大值最小值的问题。
首先扫一遍找到最大值,假设位置位于m,值为Mx。
那么向左向右各扫一遍,求出Mx为最大值的时候的次大值然后顺便更新一下答案。
然后solve(l,m-1); solve(m+1,r);

struct AAA{    int res;    void solve(int l,int r){        int i,mid=l,Mx,mx1;        for (i=l; i<=r; i++)if (a[i]>a[mid])mid=i;        if (mid-1>l)solve(l,mid-1);         if (mid+1<r)solve(mid+1,r);        Mx=a[mid];        mx1=a[mid-1]; res=max(res,Mx^mx1);        for (i=mid-1; i>=l; i--)if (a[i]>mx1){            mx1=a[i];            res=max(res,Mx^mx1);        }        mx1=a[mid+1]; res=max(res,Mx^mx1);        for (i=mid+1; i<=r; i++)if (a[i]>mx1){            mx1=a[i];             res=max(res,Mx^mx1);        }       }    void sol(){        solve(1,n);        printf("%d\n",res);    }}pianfen;

单调栈

字面意思直接把每一对最大值和次大值整出来就好了

int main(){    read(n);    int i;    for (i=1; i<=n; i++)read(a[i]);    int top=0;    for (i=1; i<=n; i++){        for (; top&&a[i]>st[top]; top--)res=max(res,a[i]^st[top]);        if (top)res=max(res,a[i]^st[top]);        st[++top]=a[i];    }    top=0;    for (i=n; i>=1; i--){        for (; top&&a[i]>st[top]; top--)res=max(res,a[i]^st[top]);        if (top)res=max(res,a[i]^st[top]);        st[++top]=a[i];    }    printf("%d",res);    return 0;}

反思

没有想到单调栈其实是很可惜的,因为写分治的时候就觉得万一出数据卡一卡就会被打回O(n^2)了然后整场比赛都挺担心第一题。
好在没有特地出数据卡。
这里写图片描述


T2 原子的裂变

题意

用一个n位数来表示一个原子,每一位的数字大小∈[0,n],可以拥有前导0但是不能全是0。
现在一个长度为n的数,裂变后第一位表示这个数有几个1,第二位表示有几个2,依次。
例如:1104
裂变后就变成2001 (2个1,0个2,0个3,1个4)

有T组数据。对于每一组数据
读入一个n位数,求有多少个n位数可以裂变成它。

n<=9;T=100。

分析

p50

首先是暴力。比如对于now(一个n位数)来说。
cnt[i]表示第i位的数字是多大。
能变成他的必然满足有cnt[i]个i。然后就变成求一个排列。
写的是BFS表示方案,DFS求排列。

//dfsvoid dfs(string s,int last,int sum){    if (sum>last)return;    if (last==0){if (!mp[s]){mp[s]=1;q.push(s);}return;}    int i;    if (last>sum){        s1=s;        s1+='0';        dfs(s1,last-1,sum);    }    for (i=1; i<=len; i++)if (cnt[i]){        s1=s;        s1+='0'+i;        cnt[i]--;        dfs(s1,last-1,sum-1);        cnt[i]++;    }   }//bfsvoid bfs(){    for (; !q.empty(); res++){        sum=0;        now=q.front(); q.pop();        for (i=0; i<len; i++)cnt[i+1]=now[i]-'0',sum+=cnt[i+1];        if (sum>len)continue;        dfs("",len,sum);    }}

p100

可以把所有数分成两类。
第一类是sum[cnt[i]]>n的,就当它为B类数,这类数字不能由其他的裂变而来。res=1
第二类是sum[cnt[i]]<=n的,就当它为A类数。res=所有可以一步变成它的res之和。

可以发现一个数的裂变过程中是不会产生环的。
除了1后面跟(n-1)个0的情况下会有一个自环,判掉就好了。

对于一个A类数,如果有一个B类数能转化成它,那么能转化成它的就全都是B类数。这里求个排列数就好了。
如果不是,那就强行求排列再往下递归就好了。

来自某同学的友情提供:即使是n=9的情况下,A类数的个数大约在40000左右。

#include<bits/stdc++.h>using namespace std;int n;int jiecheng[10];int solve(int x){    int a[10],cnt[10];    memset(a,0,sizeof(a));    memset(cnt,0,sizeof(cnt));    int k=0,l=0,tmp,i,j,res=0,t=x;    for (i=n; i>=1; i--){tmp=t%10;cnt[i]=tmp;k+=tmp;l+=tmp*i;t/=10;}    if (k>n)return 1;    if (l>n){        res=jiecheng[n];        for (i=1; i<=n; i++)res/=jiecheng[cnt[i]];        return res/jiecheng[n-k]+1;         }    int id=n-k;    for (i=1; i<=n; i++){        for (j=1; j<=cnt[i]; j++)a[id++]=i;    }       int s;s=0;    for (i=0; i<n; i++)s=s*10+a[i];    if (s!=x)res+=solve(s);         for (; next_permutation(a,a+n);){        s=0;        for (i=0; i<n; i++)s=s*10+a[i];        if (s!=x)res+=solve(s);         }    return res+1;}char s[15];int main(){    int t,l,i;    scanf("%d",&t); jiecheng[0]=1;    for (i=1; i<=9; i++)jiecheng[i]=jiecheng[i-1]*i;    for (l=1; l<=t; l++){        scanf("%s",s); n=strlen(s); int x=0;        for (i=0; i<n; i++)x=x*10+(s[i]-'0');        printf("Case #%d: %d\n",l,solve(x));            }    return 0;   }

反思

其实这道题还是挺满意的?水到了意料之外的75,一开始还以为只有50的,看来数据没有出长度全是最大值还都是100…0的情况。

T3 巧克力

题意

有n个旅游团。每个团都有a[i]个人。巧克力一盒有p块。吃完前不能开新的一盒。如果一个团内所有的人吃的都是新开的巧克力的话,那他们就会很开心。
求怎么分配能使开心的旅游团数量最多。
p<=4,n<=10000,a[i]<=1e9

分析

p好小Σ
p==2 所有偶数的先吃
然后奇数一人一个

p==3
所有三的倍数先吃
然后偶数一个奇数一个
最后奇数一个一个一个
cnt3+min(cnt1,cnt2)+(max(cnt1,cnt2)-min(cnt1,cnt2)+2)/3;

p==4
怎么觉得这题不算很难…?是我想错了莫?
总之4倍数的先吃。
好 吃完了。
然后剩下余数为1,2,3的
尽可能多把它们组成4的倍数。
首先22内销,然后13搞。
搞完再1111,3333,1133,1333,1113(就是1,3混起来4个)
然后最后112,332(两个1或3,加上一个2)
如果还有剩余就再res++

#include<cstdio>#include<iostream>#define M 10005using namespace std;void read(int &x){    x=0; char c=getchar();    for (; c<'0'; c=getchar());    for (; c>='0'; c=getchar())x=(x<<3)+(x<<1)+(c^'0');}int n,a[M];struct AAA{    void solve(){           int i;        for (i=1; i<=n; i++)read(a[i]);        printf("%d\n",n);    }}pianfen;struct CCC{    void solve(){        int i,res=0,cnt=0;        for (i=1; i<=n; i++){            read(a[i]);            if (a[i]&1)cnt++;               else res++;        }        printf("%d\n",res+(cnt+1)/2);    }   }p30;struct ACC{    void solve(){        int i,res=0,cnt1=0,cnt2=0;        for (i=1; i<=n; i++){            read(a[i]);            if (a[i]%3==0)res++;            if (a[i]%3==1)cnt1++;            if (a[i]%3==2)cnt2++;        }           printf("%d\n",res+min(cnt1,cnt2)+(max(cnt1,cnt2)-min(cnt1,cnt2)+2)/3);    }}p60;struct AAC{    void solve(){        int i,res=0,cnt1=0,cnt2=0,cnt3=0;        for (i=1; i<=n; i++){            read(a[i]);            if ((a[i]&3)==0)res++;            if ((a[i]&3)==1)cnt1++;            if ((a[i]&3)==2)cnt2++;            if ((a[i]&3)==3)cnt3++;        }        int num=min(cnt1,cnt3);        res+=num; cnt1-=num; cnt3-=num;        res+=cnt2/2; cnt2=cnt2&1;        int s=(cnt1+cnt3);        num=s/4;        res+=num; s&=3;        if (s>=2&&cnt2) res++,s-=2,cnt2--;        if (s||cnt2) res++;        printf("%d\n",res);         }   }p100;int main(){//  freopen("chocolate.in","r",stdin);//  freopen("chocolate.out","w",stdout);    int t,l,p;    read(t);    for (l=1; l<=t; l++){        printf("Case #%d: ",l);         read(n); read(p);        if (p==1)pianfen.solve();        if (p==2)p30.solve();        if (p==3)p60.solve();        if (p==4)p100.solve();    }    return 0;}

反思

比赛的时候只敲到60,因为p==4的情况似乎弄错了一点结果一分都没有。
有点可惜不过还算很满意了。(因为题目好像不是很难)
这里写图片描述

总结

其实。很满意啦——没了。
非要说的话这几天也在写深搜,像第二题这种把状态分类来求的做法,还是挺有用的。能有效的减掉一层枝。
然后第三题的话没水到所有分有点可惜不过也在意料之内。

原创粉丝点击