某厉害的比赛的题解(待补
2015-12-15 00:36
295 查看
北航第十一届程序设计竞赛网络预赛题解
比赛链接:
https://biancheng.love/contest-ng/index.html#/29官方题解
http://sd-invol.github.io/2015/12/15/BCPC2015-Online/A.模式
https://biancheng.love/problem/212/index对于窝这个外校成员,这道题好麻烦啊= =
不过我发现我可以点开别的用户的ID,看到学号。
然后再猜一猜,就知道了计算机系应该是XX06XXXX,软件学院是XX21XXXX
代码
#include<iostream> #include<stdio.h> using namespace std; string s; int main() { while(cin>>s) { if(s[2]=='0'&&s[3]=='6') cout<<"SCSE"<<endl; else if(s[2]=='2'&&s[3]=='1') cout<<"SOFT"<<endl; else cout<<"OTHER"<<endl; } }
B.并联变阻器
https://biancheng.love/problem/199/index题意即统计满足a,b≤N且aba+b是整数的二元组(a,b)的个数,条件也即a,b≤N且(a+b)|ab。
令r=gcd(a,b),则有gcd(ar,br)=1,再令a=rx,b=ry,那么(a+b)|ab 可以表示为r(x+y)|r2xy,也就是(x+y)|rxy。
由于x与y互质,所以gcd(x+y,x)=gcd(x+y,y)=gcd(x,y)=1,(x+y)与x,y也是互质的,则必然有(x+y)|r。
令r=k(x+y),则a=kx(x+y),b=ky(x+y),可以发现a,b≤N对应着x,y≤N−−√,只需要枚举不超过N−−√的互质数对(x,y),即可计算出对应的每一组解,这样做的时间复杂度是O(N−−√2)=O(N)的,其中求最大公约数的部分可以通过预处理达到O(1)。
注意到本题的数据组数较大,单组数据使用O(N)算法也会超时,但是枚举所有解的时候也确定了这组解是属于N≥max(a,b)的所有N,所以将这组(a,b)统计到对应的max(a,b),再求一遍前缀和即可得到所有答案,预处理复杂度O(N),单点查询O(1)。
代码
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6; int vis[maxn + 50] ,p[maxn + 50],sum[maxn + 50]; int quick_pow(int x , int y){ int res=1; while(y){ if(y&1) res*=x; x*=x; y>>=1; } return res; } int main() { for(int i = 1 ; i <= maxn ; ++ i) p[i] = 1; for(int i = 2 ; i <= maxn ; ++ i) if(!vis[i]){ for(int j = i ; j <= maxn ; j += i){ vis[j] = 1; int t = 0 , x = j; while(x % i == 0) x/=i , t ++ ; t=t>>1; p[j]*=quick_pow( i , t ); } } for(int i = 1 , a , b ; i <= maxn ; ++ i){ int y = i / p[i] , z = i / p[i] / p[i]; for(int j = 1 ; ((a = i + y * j) <= maxn) && ((b = j*y + j * j * z) <= maxn) ; ++ j) sum[max(a,b)]++; } for(int i = 1 ; i <= maxn ; ++ i) sum[i] += sum[i-1]; int n ; while(~scanf("%d",&n)) printf("%d\n",sum ); return 0; }
D.最大公约数
https://biancheng.love/problem/201/index贪心。
首先要意识到,最后答案每一段的GCD,一定和整个的GCD是一样的。
所以就直接扫一遍就好了。
代码
#include<iostream> #include<stdio.h> using namespace std; #define maxn 100005 int a[maxn]; int gcd(int A,int B) { if(B==0)return A; return gcd(B,A%B); } int main() { int n; while(scanf("%d",&n)!=EOF) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); int Ans = a[1]; for(int i=1;i<=n;i++) Ans = gcd(Ans,a[i]); int ans = 0; int tmp = 0; for(int i=1;i<=n;i++) { if(tmp == 0) tmp = a[i]; tmp = gcd(tmp,a[i]); if(tmp == Ans) { ans++; tmp = 0; } } printf("%d\n",ans); } }
E.矩阵
https://biancheng.love/problem/202/index就给你2500个方程,一共有100个未知数,然后每个方程里面只有两个未知数,每个未知数的系数都是1,
问你这个方程是否存在一组解。
大概一眼看到的算法大概就是算一下矩阵的秩,判断他和增广矩阵的秩是否相同就好了
然而窝TLE了= =
所以还是老老实实写差分约束吧,按照差值建边之后,再跑spfa,判断是否有负环就好了
我的判断方法比较偷懒,因为spfa有负环的话,会一直跑下去,所以我只要判断他是否会一直跑下去就好了
代码
#include<iostream> #include<stdio.h> #include<cstring> #include<vector> #include<queue> using namespace std; #define maxn 110 vector<pair<int,int> > E[maxn]; int vis[maxn]; int inq[maxn]; int d[maxn]; int main() { int n,m,k; while(cin>>n>>m>>k) { int flag = 0; for(int i=0;i<maxn;i++) E[i].clear(); memset(d,0,sizeof(d)); memset(vis,0,sizeof(vis)); memset(inq,0,sizeof(inq)); for(int i=0;i<k;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); E[x].push_back(make_pair(n+y,z)); E[n+y].push_back(make_pair(x,-z)); } queue<int> Q; for(int i=1;i<=n+m;i++) { d[i]=999999; E[0].push_back(make_pair(i,0)); } Q.push(0);inq[0]=1; int step = 0; while(!Q.empty()) { step++; if(step>1000000){ flag = 1; break; } int now = Q.front(); vis[now]=1; Q.pop(); inq[now]=0; for(int i=0;i<E[now].size();i++) { int next = E[now][i].first; if(d[next]>d[now]+E[now][i].second) { d[next]=d[now]+E[now][i].second; if(inq[next])continue; inq[next]=1; Q.push(next); } } } if(flag)printf("No\n"); else printf("Yes\n"); } }
F.序列
https://biancheng.love/problem/203/index打表找规律,很容易发现答案 = (n+1)!/2
代码
#include<bits/stdc++.h> using namespace std; #define maxn 100005 const int mod = 1e9+7; long long ans[maxn]; int main() { ans[1]=1; for(int i=2;i<maxn;i++) ans[i]=(ans[i-1]*(i+1))%mod; int n; while(cin>>n) cout<<ans <<endl; }
H.高中数学题
https://biancheng.love/problem/205/index首先手动推公式,很容易发现An = 2n + 1
然后我们再打表An的前缀异或,然后很容易发现规律
long long get(long long x) { if(x%4==0)return 2LL*x; if(x%4==1)return 3LL; if(x%4==2)return 2LL*x+2LL; if(x%4==3)return 1LL; }
所以,我们就直接跑就好了~
代码
#include<bits/stdc++.h> using namespace std; long long get(long long x) { if(x%4==0)return 2LL*x; if(x%4==1)return 3LL; if(x%4==2)return 2LL*x+2LL; if(x%4==3)return 1LL; } int main() { int t;scanf("%d",&t); while(t--) { long long l,r; scanf("%lld%lld",&l,&r); printf("%lld\n",get(l-1)^get(r)); } }
I.神奇宝贝大师
https://biancheng.love/problem/206/index费马点,曼哈顿版本。
所以X轴与Y轴是分开的。
非常裸的一道题,由于这道题的数据范围只有2000,就更加裸了……
直接暴力n^2扫就好了。
代码
#include<bits/stdc++.h> using namespace std; #define maxn 2005 long long numx[maxn]; long long numy[maxn]; int main() { int t;scanf("%d",&t); while(t--) { memset(numx,0,sizeof(numx)); memset(numy,0,sizeof(numy)); int n,m; scanf("%d%d",&n,&m); int x,y,q; scanf("%d%d%d",&x,&y,&q); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { numx[i]+=((x^i)+(y^j))%q; numy[j]+=((x^i)+(y^j))%q; } } long long minx=9999999999999LL,miny=9999999999999LL; for(int i=1;i<=n;i++) { long long temp = 0; for(int j=1;j<=n;j++) temp += numx[j]*abs(j-i); if(temp<minx) minx = temp; } for(int i=1;i<=m;i++) { long long temp = 0; for(int j=1;j<=m;j++) temp += numy[j]*abs(j-i); if(temp<miny) miny = temp; } printf("%lld\n",minx+miny); } }
L.偶回文串
https://biancheng.love/problem/198/index这道题是水题
回文即满足所有字母都是偶数即可
我们利用异或,来统计每一种状态的数量,那么这个状态对答案的贡献就是(num-1)*(num)/2
所以这道题就结束了。
代码
#include<iostream> #include<stdio.h> #include<cstring> #include<vector> #include<queue> #include<map> using namespace std; map<int,long long> H; string s; int main() { while(cin>>s) { H.clear(); int k = 0; H[k]++; for(int i=0;i<s.size();i++) { k^=(1<<(s[i]-'a')); H[k]++; } map<int,long long>::iterator it; long long ans = 0; for(it = H.begin();it!=H.end();it++) { long long p = it->second; ans += (p-1)*p/2; } printf("%lld\n",ans); } }
M.我是鱼
https://biancheng.love/problem/210/index这道题涨姿势了,一开始我只能想到hash。
一直没想到怎么只用xor来解决……
官方题解写的比较清楚:
一个数和自己异或(⊕)结果为0,所以如果只有一个数是奇数全部异或起来就能得到结果,如果有两个数是奇数,假设为a,b,把所有数异或起来的结果等于a⊕b,设c=a⊕b,则c≠0,c的二进制表示中必有某一位为1,假设为第x位,那么将所有第x位为0的异或起来,所有为1的异或起来就能得到a,b。
代码
#include<iostream> #include<stdio.h> using namespace std; #define maxn 1000005 long long a[maxn]; int main() { int n; while(cin>>n) { long long x=0; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); x^=a[i]; } int flag = 0; for(int i=0;i<60;i++) { if((x>>i)&1) { flag = i; break; } } long long ans1 = 0,ans2 = 0; for(int i=1;i<=n;i++) { if((a[i]>>flag)&1)ans1^=a[i]; else ans2^=a[i]; } if(ans1>ans2)swap(ans1,ans2); printf("%lld %lld\n",ans1,ans2); } }
相关文章推荐
- 通过javascript在网页端解压zip文件并查看压缩包内容
- Android之放大镜实现的两种方式
- Python爬虫教程——实战二三四五
- Git之如何解决sourceTree已经pull全部下来但是本地没有更新的问题
- 【Java.Apache.Camel】
- LeetCode 101:Symmetric Tree
- 通过style样式实现动态显示与隐藏
- UVA-11613 Acme Corporation (最大费用最大流+拆点)
- Beta版本冲刺第六天
- Python爬虫教程——进阶一之爬虫框架Scrapy安装配置
- Linux用户和组命令总结
- 源码探索系列3---四大金刚之Activity的启动过程完全解析
- Python爬虫教程——实战一之爬取糗事百科段子
- HDOJ--1007
- 设计模式之单例模式
- HDU 1049 青蛙爬进 (水题_模拟)
- 剑指offer:丑数
- ContentProvider启动时机问题简记
- Linux用户和用户组基本概念
- 单调队列 hdu3401 Trade