牛客算法周周练6 题解【B-E】
B 华华对月月的忠诚:
试着打了打表,发现只跟gcd(a,b)有关,所以直接输出gcd(a,b)就可以了。
但是作为题解要数学证明,我在别人的博客那发现了证明:
https://blog.nowcoder.net/n/69e53616e1444d399be566a360061220
大家想要看数学证明的可以去看看。
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<vector> #include<cstring> #define fs first #define se second #define pb push_back #define cppio ios::sync_with_stdio(false);cin.tie(0) using namespace std; typedef long long ll; typedef pair<int,int> pii; typedef vector<int> VI; const int maxn=1e6+6; const ll inf=0x3f3f3f3f; const ll mod=1e9+7; char s[maxn]; ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); } int main(){ ll a,b; scanf("%lld%lld%s",&a,&b,&s); printf("%lld",gcd(a,b)); return 0; }
C. Game
很基础的质因数分解,然后直到什么时候分解不了了就输出就好了。
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<vector> #include<cstring> #define fs first #define se second #define pb push_back #define cppio ios::sync_with_stdio(false);cin.tie(0) using namespace std; typedef long long ll; typedef pair<int,int> pii; typedef vector<int> VI; const int maxn=1e6+6; const ll inf=0x3f3f3f3f; const ll mod=1e9+7; int a[maxn]; int check(int num){ for(int i=2;i*i<=num;i++){ if(num%i==0){ return num/i; } } return 0; } int main(){ int n; scanf("%d",&n); int flg=0; while(1){ int tmp=check(n); if(tmp==0) break; n=tmp; flg++; } if(flg%2==1){ printf("Johnson\n"); } else{ printf("Nancy\n"); } return 0; }
D 挖沟
超级明显的最小生成树题,有两种算法:普利姆和克鲁斯卡尔,复杂度分别是O(n²)和O(mlogm)。所以这次的是要用克鲁斯卡尔。
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<vector> #include<cstring> #include<queue> #define fs first #define se second #define pb push_back #define cppio ios::sync_with_stdio(false);cin.tie(0) using namespace std; typedef long long ll; typedef pair<int,int> pii; typedef vector<int> VI; const int maxn=1e6+6; const ll inf=0x3f3f3f3f; const ll mod=1e9+7; int fa[maxn]; void init() { for(int i = 0;i<=maxn;i++){ fa[i]=i; } } int find(int x) { return (fa[x] == x)?x:fa[x] = find(fa[x]); } void merge(int y,int x) { int xx = find(x),yy = find(y); if(xx != yy) fa[xx] = yy; } struct Node{ int x,y,val; Node(int x,int y,int val):x(x),y(y),val(val){ } bool operator<(const Node& bb)const{ return val>bb.val; } }; int main(){ init(); int n,m; scanf("%d%d",&n,&m); priority_queue<Node> q; for(int i=1;i<=m;i++){ int x,y,val; scanf("%d%d%d",&x,&y,&val); q.push(Node(x,y,val)); } int ans=0; while(!q.empty()){ int x=q.top().x;int y=q.top().y;int val=q.top().val; q.pop(); int xx=find(x);int yy=find(y); if(xx!=yy){ fa[yy]=xx; ans+=val; } } printf("%d\n",ans); return 0; }
E 签到题
E是最有意思的题了,主要看大家是否看到这句话:保证数据随机生成。
一般看到这句话就意识到:暴力说不定能行。
然后试着暴力一发,A了。
正常的时间复杂度:如果随机的话,平均的L-R长度为1e5/2,有N次操作,那么应该是1e9的时间复杂度,但是随机嘛肯定会小点,所以暴力是能过的,脸黑的就再交一次。
#include <algorithm> #include <iostream> #include <cstring> #include <climits> #include <cstdio> #include <vector> #include <cstdlib> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #define fi first #define lc (x<<1) #define se second #define U unsigned #define rc (x<<1|1) #define Re register #define LL long long #define MP std::make_pair #define CLR(i,a) memset(i,a,sizeof(i)) #define FOR(i,a,b) for(Re int i = a;i <= b;++i) #define ROF(i,a,b) for(Re int i = a;i >= b;--i) #define SFOR(i,a,b,c) for(Re int i = a;i <= b;i+=c) #define SROF(i,a,b,c) for(Re int i = a;i >= b;i-=c) #define DEBUG(x) std::cerr << #x << '=' << x << std::endl const int MAXN = 1000000+5; int N,maxL; std::set<std::pair<int,int> > L; inline int calc(){ // 返回 set 中所有线段的并长度。(每个 pair 表示一个线段[first,second] } int tmp[MAXN]; int main(){ scanf("%d%d",&N,&maxL); int res=0; while(N--){ int opt,x,y; scanf("%d%d%d",&opt,&x,&y); if(opt == 1){ if(L.find(MP(x,y)) != L.end()) continue; L.insert(MP(x,y)); for(int i=x;i<=y;i++){ tmp[i]++; res+=tmp[i]==1; } } if(opt == 2){ if(L.find(MP(x,y)) == L.end()) continue; L.erase(MP(x,y)); for(int i=x;i<=y;i++){ tmp[i]--; res-=tmp[i]==0; } } if(opt == 3){ printf("%d\n",res); } } return 0; }