牛客练习赛8解题报告
来源:互联网 发布:国泰安数据库好不好用 编辑:程序博客网 时间:2024/05/29 07:53
A. 约数个数的和
题目大意:求1~n中每个数的约数个数之和
简要题解:经典问题,考虑每个数是多少个数的约数,ans=∑n/i
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>using namespace std;int n,ans;int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) ans+=n/i; printf("%d\n",ans); return 0;}
B. 储物点的距离
题目大意:数轴上有n个点,第i个点和第i+1个点相距s[i],第i个点有xi个物品,m次询问,求把第l个点到第r个点之间的物品运到第x个点的代价。
简要题解:前缀和记录一下xi和xi*si即可
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#define maxn 200010#define mod 1000000007using namespace std;long long a[maxn],b[maxn],s[maxn];int n,m;int main(){ scanf("%d%d",&n,&m); for (int i=2;i<=n;i++) scanf("%lld",&a[i]),a[i]=(a[i]+a[i-1])%mod; for (int i=1;i<=n;i++) scanf("%lld",&b[i]),s[i]=a[i]*b[i]%mod,b[i]=(b[i]+b[i-1])%mod,s[i]=(s[i]+s[i-1])%mod; while (m--) { int x,l,r; scanf("%d%d%d",&x,&l,&r); long long ans=0; if (x>l && x<r) ans=a[x]*(b[x]-b[l-1])-(s[x]-s[l-1])+(s[r]-s[x])-a[x]*(b[r]-b[x]); else if (x<=l) ans=(s[r]-s[l-1])-a[x]*(b[r]-b[l-1]); else ans=a[x]*(b[r]-b[l-1])-(s[r]-s[l-1]); ans=(ans%mod+mod)%mod; printf("%lld\n",ans); } return 0;}
C. 回文串的交集
题目大意:给定一个字符串,求有多少对回文子串相交。
简要题解:补集转化,求不相交的回文子串有多少对,则枚举分界线即可。
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#define maxn 2000010#define mod 1000000007using namespace std;char s[maxn];int p[maxn],cnt[maxn],L[maxn],R[maxn];int n,m,ans;int main(){ scanf("%d%s",&n,s+1); s[0]='-';s[n+1]='+'; int mx=0,id=0; for (int i=1;i<=n;i++) { if (mx>i) p[i]=min(mx-i,p[2*id-i]); else p[i]=1; while (s[i-p[i]]==s[i+p[i]]) p[i]++; if (i+p[i]>mx) mx=i+p[i],id=i; ans=(ans+p[i])%mod; cnt[i]++;cnt[i+p[i]]--; L[i-p[i]+1]++;L[i+1]--; } mx=0,id=0; for (int i=1;i<=n;i++) { if (mx>i) p[i]=min(mx-i,p[2*id-i]); else p[i]=0; while (s[i-p[i]]==s[i+p[i]+1]) p[i]++; if (i+p[i]>mx) mx=i+p[i],id=i; ans=(ans+p[i])%mod; L[i-p[i]+1]++;L[i+1]--; cnt[i+1]++;cnt[i+p[i]+1]--; } ans=1ll*ans*(ans-1)/2%mod; for (int i=1;i<=n;i++) cnt[i]=(cnt[i]+cnt[i-1])%mod,L[i]=(L[i]+L[i-1])%mod; //for (int i=1;i<=n;i++) printf("%d ",cnt[i]);printf("\n"); for (int i=n;i>=1;i--) R[i]=(R[i+1]+L[i])%mod; for (int i=1;i<n;i++) ans=(ans-1ll*cnt[i]*R[i+1]%mod+mod)%mod; printf("%d\n",ans); return 0;}
D. 加边的无向图
题目大意:给定一个无向图,至少求加入多少条边可使其联通。
简要题解:ans=n-联通块个数
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#define maxn 100010using namespace std;int n,m,cnt;int f[maxn];int find(int i) {return f[i]==i?i:f[i]=find(f[i]);}int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) f[i]=i; for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); f[find(x)]=find(y); } for (int i=1;i<=n;i++) if (f[i]==i) cnt++; printf("%d\n",cnt-1); return 0;}
E. 集合中的质数
题目大意:给定一个包含n个质数的集合S,求1~m中有多少个数能被至少一个质数整除。
简要题解:容斥,枚举被选中的质数,注意爆long long。这里如果用除法,可以避免溢出问题。
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>using namespace std;long long a[21],m,ans;int n;void dfs(int i,long long now,long long t){ if (i==n) {ans+=m/now*t;return;} i++; dfs(i,now,t); if (log(now)+log(a[i])<log(m)+0.1) dfs(i,now*a[i],-t);}int main(){ scanf("%d%lld",&n,&m); for (int i=1;i<=n;i++) scanf("%lld",&a[i]); dfs(0,1,1); printf("%lld\n",m-ans); return 0;}
F. 重排的回文串
题目大意:长度为n只包含小写字母的字符串,m组询问,求[l,r]中有多少个子串可以重排为字符串。
简要题解:注意到是否可以重排为字符串,只与字母出现次数有关,具体些,至于每种字母出现次数的奇偶性有关。于是,可以处理出每种字母出现次数奇偶性的前缀状态,状态数为2^26,最多有O(n)种,这里可以离散化。离线莫队,维护当前区间每种状态的出现次数,以l为右端点的答案数为cnt[S[l]]+cnt[S[l]^(1<<0)]+……+cnt[S[l]^(1<<25)]
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#include<map>#define maxn 60010using namespace std;struct yts{ int l,r,id;}q[maxn];int a[maxn],b[maxn],r[maxn],cnt[maxn];char s[maxn];long long ans,ANS[maxn];int num,head[maxn*26],nxt[maxn*26],to[maxn*26];int n,m,block;map<int,int> mp;bool cmp(yts x,yts y){ if ((x.l-1)/block!=(y.l-1)/block) return x.l<y.l; return x.r<y.r;}long long calc(int x){ long long ans=cnt[x]; for (int p=head[x];p;p=nxt[p]) ans+=cnt[to[p]]; return ans;}void addedge(int x,int y){ num++;to[num]=y;nxt[num]=head[x];head[x]=num;}int main(){ scanf("%d%d",&n,&m); scanf("%s",s+1); block=(int)sqrt(n); for (int i=1;i<=n;i++) a[i]=a[i-1]^(1<<s[i]-'a'),b[i]=a[i]; b[n+1]=0; sort(b+1,b+n+2); int Q=unique(b+1,b+n+2)-b-1; for (int i=1;i<=Q;i++) mp[b[i]]=i; for (int i=0;i<=n;i++) r[i]=mp[a[i]]; for (int i=1;i<=Q;i++) for (int j=0;j<26;j++) if (mp.find(b[i]^(1<<j))!=mp.end()) addedge(i,mp[b[i]^(1<<j)]); for (int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i; sort(q+1,q+m+1,cmp); int L=1,R=0; for (int i=1;i<=m;i++) { while (L<q[i].l) cnt[r[L]]--,ans-=calc(r[L++]); while (L>q[i].l) ans+=calc(r[--L]),cnt[r[L]]++; while (R>q[i].r) cnt[r[R]]--,ans-=calc(r[R--]); while (R<q[i].r) ans+=calc(r[++R]),cnt[r[R]]++; ANS[q[i].id]=ans+calc(r[q[i].l-1]); } for (int i=1;i<=m;i++) printf("%lld\n",ANS[i]); return 0;}
题目比较简单,写题解主要是为了练一下markdown。以后尽量用markdown来写博客。
阅读全文
0 0
- 牛客练习赛8解题报告
- 20111023练习赛解题报告
- 2011新生练习赛三解题报告
- 数论基础练习赛-解题报告
- HLJU@贪心练习 解题报告
- CCNU 2010新生练习赛1解题报告
- 华工腾讯俱乐部新生练习赛(二)解题报告
- 第一次练习赛解题报告及标程
- 2013级数据结构第二次练习赛解题报告
- 第三次练习赛解题报告及标程
- 第四次练习赛解题报告及标程
- 第五次练习赛解题报告及标程
- 第六次练习赛解题报告及标程
- 第七次练习赛解题报告及标程
- HPUACM2014级第三周练习赛解题报告
- ACM pku 1003 解题报告(练习输入输出)
- zsacm第一期网络练习解题报告
- 最短路入门练习 解题报告
- effective C++ 11_在operator= 中处理"自我赋值" 读书笔记
- 3-10·Linux服务管理
- jenkins
- 浅谈list的remove方法
- memcache
- 牛客练习赛8解题报告
- jsp登录页面
- Spring--装配Bean
- 【Python数据分析与展示】(七)数据加载存储和文件格式
- [RK3399][Android7.1] 调试笔记 --- 默认板子无法亮屏
- AnimatorSet 动画集合以及它的监听事件
- 《Java编程技巧1001条》360条:用日期函数获得当前日期
- ACRUSH 楼教主的回忆录
- jQuery 遍历