B:华华对月月的忠诚
思路:因为最后要求的是gcd(a,b),所以我一开始是分类讨论的。
如果a和b都是偶数,那么他们的斐波拉契项都是偶数,对于任意位置的n和n+1,偶数的gcd都是2.
如果a和b都是奇数,或者是奇数与偶数,他们的斐波拉契项有可能有奇数或者偶数,一开始我猜想都是1,事实上大部分都是1,但是随手打了个表就找到了反例,a=3,b=9,然后我就发现事实上这个答案就是gcd(a,b)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
void solved(){
ll a,b,n;cin>>a>>b>>n;
cout<<__gcd(a,b)<<endl;
}
int main(){
solved();
return 0;
} D:挖沟
这个题。。。。。裸的最小生成树。。直接上板子就行。
克鲁斯卡尔算法:存边,对边权排序,选择n-1条最小边,并且不构成回路(并查集维护).
好久没写最小生成树了,现场花了几分钟手搓了一下
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn = 5e5 + 10;
struct edge{
int u,v,w;
edge(){}
edge(int a,int b,int c):u(a),v(b),w(c){}
}a[maxn];
int f[maxn];
bool cmp(edge a,edge b){
return a.w < b.w;
}
int find(int x){
if(f[x] != x){
return f[x] = find(f[x]);
}
return x;
}
void solved(){
int n,m;cin>>n>>m;
for(int i = 1; i <= n; i++)f[i] = i;
for(int i = 1; i <= m; i++){
int u,v,w;cin>>u>>v>>w;
a[i] = {u,v,w};
}
sort(a + 1 ,a + 1 + m,cmp);
int tot = 0;
ll ans = 0;
for(int i = 1; i <= m; i++){
int u = a[i].u,v = a[i].v;
int fa = find(u);
int fb = find(v);
if(fa != fb){
f[fa] = fb;
tot++;
ans += a[i].w;
}
if(tot == n - 1)break;
}
cout<<ans<<endl;
}
int main(){
solved();
return 0;
}C:Game
思路:这题从一次操作可以将集合中一个数字分解为它的任意两个非1的因数入手,首先我们可以考虑特殊的数-素数,只能分解为1*n,所以先手必败,然后再思考普遍的情况。对于一个数,我们可以一直把他拆开,直到不能再拆为止,记录我们拆的次数,如果是奇数说明后手无法继续拆,偶数先手无法拆,输出对应答案即可。
代码:
#include<bits/stdc++.h>
using namespace std;
bool is_prime(int n){
for(int i = 2; i * i <= n; i++){
if(n % i == 0)return false;
}return true;
}
void solved(){
int n;cin>>n;
if(is_prime(n)){cout<<"Nancy"<<endl;return;}
queue<int>st;st.push(n);
int cnt = 0;
while(!st.empty()){
int cur = st.front();st.pop();
for(int i = 2; i * i <= cur; i++){
if(cur % i == 0){
cnt++;
st.push(i);st.push(cur / i);break;
}
}
}
if(cnt & 1)cout<<"Johnson"<<endl;
else cout<<"Nancy"<<endl;
}
int main(){
solved();
return 0;
} E:签到题
思路:看到题直接就认为是记录每个数出现的次数,然后上线段树。。。。导致浪费好多时间。。还是先应该认真看题啊。。。题目意思是插入n段区间要我们就所有区间的并的个数,删除的区间必须是先前插入过的才行。
区间修改,区间求和,所以我们可以用线段树来维护,线段树维护cnt表示插入删除的次数,len表示当前区间长度。如果cnt为真说明这段区间已经插入过了,它的区间长度就是本身,否则,它的区间长度等于左右儿子的长度之和。如果插入的区间与已有的区间重合怎么处理?对于重合的区间说明之前已经插入过,它的cnt为真所以不用处理,就变成了只对没重合的处理。
代码:
#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
using namespace std;
const int MAXN = 1000000+5;
int N,maxL;
std::set<std::pair<int,int> > L;
const int maxn = 1e6 + 10;
struct seg{
int l,r,cnt;
int len;
seg(){}
seg(int a,int b):l(a),r(b){}
}tree[maxn << 2];
void build(int rt,int l,int r){
tree[rt] = {l,r};
if(l == r){
tree[rt].len = 0;
tree[rt].cnt = 0;
return;
}
int mid = l + r >> 1;
build(rt << 1,l, mid);
build((rt << 1) + 1,mid + 1,r);
tree[rt].cnt = 0;
tree[rt].len = 0;
}
void update(int rt ,int l,int r,int v){
if(tree[rt].l >= l && tree[rt].r <= r){
tree[rt].cnt += v;
if(tree[rt].cnt)tree[rt].len = (tree[rt].r - tree[rt].l + 1);
else {tree[rt].len = tree[rt << 1].len + tree[rt << 1 | 1].len;}
return ;
}
int mid = tree[rt].l + tree[rt].r >> 1;
if(r <= mid) update(rt << 1,l,r,v);
else if(l > mid) update((rt << 1) + 1,l,r,v);
else update(rt << 1,l,r,v),update((rt << 1) + 1,l,r,v);
if(tree[rt].cnt)tree[rt].len = (tree[rt].r - tree[rt].l + 1);
else {tree[rt].len = tree[rt << 1].len + tree[rt << 1 | 1].len;}
}
int main(){
scanf("%d%d",&N,&maxL);
build(1,1,maxL);
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));
update(1,x,y,1);
}
if(opt == 2){
if(L.find(MP(x,y)) == L.end()) continue;
L.erase(MP(x,y));
update(1,x,y,-1);
}
if(opt == 3){
printf("%d\n",tree[1].len);
}
}
return 0;
}
京公网安备 11010502036488号