20171009模拟赛总结
2017-10-10 10:25
225 查看
来源:不知道
分数:100+75+60
rank:10
n<=2*10^6
然后就来看区间内最大值和次大值有什么特点了。
其实关于这类问题做得应该不算少了。大概有两种方法。
首先扫一遍找到最大值,假设位置位于m,值为Mx。
那么向左向右各扫一遍,求出Mx为最大值的时候的次大值然后顺便更新一下答案。
然后solve(l,m-1); solve(m+1,r);
好在没有特地出数据卡。
现在一个长度为n的数,裂变后第一位表示这个数有几个1,第二位表示有几个2,依次。
例如:1104
裂变后就变成2001 (2个1,0个2,0个3,1个4)
有T组数据。对于每一组数据
读入一个n位数,求有多少个n位数可以裂变成它。
n<=9;T=100。
cnt[i]表示第i位的数字是多大。
能变成他的必然满足有cnt[i]个i。然后就变成求一个排列。
写的是BFS表示方案,DFS求排列。
第一类是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左右。
求怎么分配能使开心的旅游团数量最多。
p<=4,n<=10000,a[i]<=1e9
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++
有点可惜不过还算很满意了。(因为题目好像不是很难)
非要说的话这几天也在写深搜,像第二题这种把状态分类来求的做法,还是挺有用的。能有效的减掉一层枝。
然后第三题的话没水到所有分有点可惜不过也在意料之内。
分数: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求排列。
//dfs void 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]++; } } //bfs void 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 ; 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 d16f +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 10005 using 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的情况似乎弄错了一点结果一分都没有。有点可惜不过还算很满意了。(因为题目好像不是很难)
总结
其实。很满意啦——没了。非要说的话这几天也在写深搜,像第二题这种把状态分类来求的做法,还是挺有用的。能有效的减掉一层枝。
然后第三题的话没水到所有分有点可惜不过也在意料之内。
相关文章推荐
- 11.1~11.2NOIP模拟赛总结
- 高二&高一&初三模拟赛23 总结
- sc2017新高二&高一模拟赛3 总结
- NOIP2017提高组 模拟赛23(总结)
- 20160521模拟赛总结
- sc2017新高二&高一模拟赛2 总结
- 11.5模拟赛总结
- 【NOIP模拟赛】总结
- 对【2017.4.15B组NOIP提高模拟赛】总结
- jzoj 模拟赛总结(2017.07.15)
- 2017.08.15【NOIP 普及组】模拟赛C组总结
- NOIP模拟赛2017.9.11 考试心得+总结
- 2017.07.11日C组模拟赛总结
- 2017.3.25NOI模拟赛总结
- 9-14NOIP模拟赛总结
- 高二&高一&初三模拟赛16 总结
- NOIP2017提高组 模拟赛18(总结)
- 信息模拟赛总结
- SSL 模拟赛 总结(2017.10.25)
- 9-30NOIP模拟赛总结