zzuli 第八届校赛 题解
来源:互联网 发布:思迅软件官方网站 编辑:程序博客网 时间:2024/06/05 06:23
准备了一个月的校赛终于没白费工夫,拿到了冠军...但是只过了9题...因为我字符串学的太差C题没过...
这套题说起来没有去年的好,虽然我去年打的不好吧。原题三四个...
还有一道比较难的数论没放出来....说起来花了五分钟就推出来公式了....导致最后两个小时都没题目做...
A.模拟
注意坑点有过程中某个值爆了int然后在凑出来一个0-255的数字,还有就是连续两个点..
B.DP
lightoj的原题,只是多了n==1或者m==1的情况,特判一下就好了...lightoj无1题解连接:点击查看
C. 字符串hash
我觉得可以二分答案用字符串hash判断,鸟神提出了一个思路是manacher+lcp...弱准备学好字符串在回来搞这个题。
D.预处理+查询区间最小值
可以先预处理出每个点被覆盖多少次,然后针对于每条线段进行枚举,查询这条线段的区间中最小值是多少,如果小于2说明只被这一条线段覆盖他被删除后肯定是没有其他线段覆盖..线段树没加优化可能会被卡..因为没有修改只有查询,所以我采用的ST算法,预处理为nlogn查询复杂度为1...针对这个题优势比较大。
代码:
#include<bits/stdc++.h>using namespace std;#define ll long longint ja[120000],j[120000],l[120000],r[120000],x[120000];int dp[120000][20],mm[120000];int ans[120000];void initrmq(int n,int b[]){ mm[0]=-1; for(int i=1;i<=n;i++) { mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; dp[i][0]=b[i]; } for(int j=1;j<=mm[n];j++) for(int i=1;i+(1<<j)-1<=n;i++) dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);}int rmq(int x,int y){ int k=mm[y-x+1]; return min(dp[x][k],dp[y-(1<<k)+1][k]);}int main(){ int t; scanf("%d",&t); while(t--) { memset(ja,0,sizeof(ja)); memset(j,0,sizeof(j)); memset(x,0,sizeof(x)); memset(dp,0,sizeof(dp)); int n,m; scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d %d",&l[i],&r[i]); ja[l[i]]++; j[r[i]]++; } int tmp=0; for(int i=1;i<=n;i++) { tmp+=ja[i]; x[i]+=tmp; tmp-=j[i]; } initrmq(n,x); int cnt=0; for(int i=1;i<=m;i++) { int tmp=rmq(l[i],r[i]); if(tmp<=1) continue; else ans[cnt++]=i; } printf("%d\n",cnt); for(int i=0;i<cnt;i++) { if(i==cnt-1) printf("%d\n",ans[i]); else printf("%d ",ans[i]); } } return 0;}E.模拟
我直接采用了0年1月1日到两个输入的日期分别有多少天然后计算差值。这样的话关于闰年比较好计算,可以用容斥...闰年数量为x/4-x/100+x/400...
#include<bits/stdc++.h>using namespace std;#define ll long longint pd(int y){ if(y%400==0) return 1; if(y%4==0&&y%100!=0) return 1; return 0;}int mf[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};int mr[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};ll js(int y,int m,int d){ ll tmp=(y-1)/4-(y-1)/100+(y-1)/400; tmp+=(y-1)*365; for(int i=1;i<m;i++) { if(i==2&&pd(y)) tmp++; tmp+=mf[i]; } tmp+=d; return tmp;}int main(){ int T; scanf("%d",&T); while(T--) { int y1,m1,d1,y2,m2,d2; scanf("%d %d %d %d %d %d",&y1,&m1,&d1,&y2,&m2,&d2); ll ans=js(y1,m1,d1); ll tmp=js(y2,m2,d2); ans=tmp-ans; printf("%lld\n",ans); } return 0;}
F.数论
首先我们要明确一点,gcd是在减法的基础上优化的...那么这个减法的过程真的很像最朴素的求gcd的过程啊..测试一发样例过了 提交试试,因为感觉直接模拟肯定爆炸。
#include<bits/stdc++.h>using namespace std;#define ll long long#define PI acos(-1.0)int a[1200];int gcd(int a,int b){ return b==0?a:gcd(b,a%b);}int main(){ int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } int ans=a[1]; int sum=a[1]; for(int i=2;i<=n;i++) { ans=gcd(ans,a[i]); sum+=a[i]; } printf("%d\n",sum/ans); } return 0;}G.折半枚举
首先这个题一眼看上去就是一个背包,然后背包的体积与价值过大..所以请参考挑战程序设计162页的超大背包求解的折半枚举方法。先把n个物品分成两堆,然后枚举出来每堆的所有状态,最大为2^15,然后将两堆都按照饱食度排序。刚开始我想的是第二堆按照饱食度为关键字建立线段树,但是价格是无序的查找太烦..然后考虑到如果用其他的的话要支持添加操作以及查询最小值和指定值,毫无疑问set最合适...
对于第一堆按照饱食度从小到大枚举,对于这个状态来言把所有饱食度与其和大于k的价格全部加入set,因为这样的话枚举后面饱食度大的情况第二堆加入的这些是肯定成立的,set里面最多加入2^15个价格。
然后查找的时候我们要查找出当前最小价格,然后看第一堆价格加最小价格是否大于x,大于x的话直接-y与当前最小值比较,否则的话我们还要选择一次第一堆价格+某个价格的值大于x且最小的...然后减去y与答案比较。
学弟用了DFS优化暴力刚好卡着时间过了...
#include<bits/stdc++.h>using namespace std;#define ll long longstruct node{ ll p,b;} s1[80000],s2[80000];ll p[50],b[50];set<ll> s;set<ll>::iterator it;int cmp(node a,node b){ return a.b<b.b;}int main(){ int t; ll n; ll k,x,y; scanf("%d",&t); while(t--) { cin>>n>>k>>x>>y; ll sum=0; for(int i=0; i<n; i++) { cin>>p[i]>>b[i]; sum+=b[i]; } if(sum<k) { puts("go die"); continue; } s.clear(); int cnt1=0; int tn=n/2; for(int i=0; i<(1<<tn); i++) { ll tmpp=0,tmpb=0; for(int j=0; j<tn; j++) { if(i&(1<<j)) { tmpp+=p[j]; tmpb+=b[j]; } } s1[cnt1].p=tmpp; s1[cnt1].b=tmpb; cnt1++; } int nt=n-tn; int cnt2=0; for(int i=0; i<(1<<nt); i++) { ll tmpp=0,tmpb=0; for(int j=0; j<nt; j++) { if(i&(1<<j)) { tmpp+=p[j+tn]; tmpb+=b[j+tn]; } } s2[cnt2].p=tmpp; s2[cnt2].b=tmpb; cnt2++; } sort(s1,s1+cnt1,cmp); sort(s2,s2+cnt2,cmp); int j=cnt2-1; ll ans=10000000000LL; ll ax; for(int i=0; i<cnt1; i++) { ll tmp=max(0LL,k-s1[i].b); while(s2[j].b>=tmp&&j>=0) { s.insert(s2[j].p); j--; } if(s.empty()) continue; ax=s1[i].p; if(ax+(*s.begin())<x) { ans=min(ans,ax+(*s.begin())); ll c=max(0LL,x-ax); it=s.lower_bound(c); if(it==s.end()) continue; ax+=(*it); ax-=y; ans=min(ans,ax); } else ans=min(ans,ax+(*s.begin())-y); } cout<<ans<<endl; } return 0;}
H.简单并查集
直接判断有多少个根,然后答案是根数-1..
#include<bits/stdc++.h>using namespace std;#define ll long long#define PI acos(-1.0)int f[2000];void db(int n){ for(int i=1;i<=n;i++) f[i]=i;}int finde(int x){ if(f[x]!=x) return f[x]=finde(f[x]); return x;}int main(){ int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d %d",&n,&m); db(n); int u,v; for(int i=0;i<m;i++) { scanf("%d %d",&u,&v); int x=finde(u); int y=finde(v); if(x!=y) f[x]=y; } int ans=0; for(int i=1;i<=n;i++) { if(f[i]==i) ans++; } printf("%d\n",ans-1); } return 0;}
I 公式题
论身边带学霸的重要性
#include<bits/stdc++.h>using namespace std;#define ll long long#define PI acos(-1.0)int main(){ int t; scanf("%d",&t); while(t--) { int n,a,l; scanf("%d %d %d",&n,&a,&l); double ans=a*a*n/4.0/tan(PI/n); int cnt=0; while(ans>l) { ans=ans*(cos(PI/n)*cos(PI/n)); cnt++; } printf("%d\n",cnt); } return 0;}
J 签到
CF原题,如果有1肯定能凑出来所有数字,如果没1的话连1都凑不出来肯定是不行的..
- zzuli 第八届校赛 题解
- 郑州大学第八届校赛热身赛题解
- 郑州大学第八届校赛正式赛题解
- zzuli 第九届ACM校赛题解
- 蓝桥杯第八届题解
- 第八届蓝桥杯题解
- LeetCode题解 第八周
- zzuli - 第七届校赛
- [ACM] 第八届西邮杯初赛题解
- 南京理工大学第八届程序设计大赛题解
- 郑州轻工业学院第八届玲珑杯校赛题解
- 第八届蓝桥杯JAVA B组省赛题解
- 《Algorithms》第八章课后习题8.10题解
- 第八届Nuist程序设计大赛 题解
- 欧拉计划网第八题解决方案
- 第八届湘潭大学程序设计比赛(题解)
- 第六届蓝桥杯C/C++A组第八题解答
- 河南省第八届ACM A.挑战密室 详细题解
- CSDN 段首缩进问题
- 单继承
- C语言指针-------通过调用函数,完成两个数值的交换
- ETL利器Kettle实战应用解析系列一【Kettle使用介绍】
- 关于SAT问题的讨论
- zzuli 第八届校赛 题解
- android客户端学习-activity
- 南京理工大学第八届程序设计大赛(校外镜像) - count_prime (容斥原理)
- 【Spring实战】—— 12 AspectJ报错:error at ::0 can't find referenced pointcut XXX
- ora-00845
- c++文件流操作
- 博客收藏地址
- 学习JAVA之路(六、数组)
- 一个选择答案功能的小Demo