A题:
思路:找规律吧,首先假设没有石墩,那么包括左岸在内,青蛙能够落脚的位置就有荷叶数+1(+1是包含左岸),青蛙按序号依次跳到右岸,那么ans=m+1
现在有若干个石墩,给青蛙提供落脚点,令n=1,n=2,n=3……很快就能发现,ans成倍数增长,那么利用二进制的左移(<<)便可以快速得到答案。
代码:
#include <bits/stdc++.h> using namespace std; int main() { long long n,m; scanf("%lld%lld",&n,&m); long long ans=m+1; ans<<=n; printf("%lld\n",ans); }
B题:
思路:一开始看到题目还以为是什么神奇的大数。。。。。。
看了几遍没有什么思路,后面来做的。
发现求最大公约数的辗转相除法跟这个递推公式有某种默契。
gcd(FN,FN+1)=gcd(FN-1,FN)
那么就可以得到,最终答案就是gcd(A,B)
所以只需要利用辗转相除法,编写递归函数,就可以得到最终的答案了,答案与N无关
需要注意的是,由于数据比较大,需要开long long,函数的参数列表也要注意用long long
代码:
#include <bits/stdc++.h> using namespace std; long long gcd(long long a,long long b) { if(b==0) return a; return gcd(b,a%b); } int main() { long long a,b,c; scanf("%lld%lld%lld",&a,&b,&c); long long d=gcd(a,b); printf("%lld\n",d); }
C题:
思路:一个质因数的分解题,判断能分解的数的奇偶性,判定谁胜谁负。
代码:
#include <bits/stdc++.h> using namespace std; int main() { int n; scanf("%d",&n); if(n==1) { printf("Nancy\n"); return 0; } int num=0; for(int i=2;i<=n;i++) { while(n%i==0) { num++; n/=i; } } if((num&1)==0) { printf("Johnson\n"); } else printf("Nancy\n"); }
D题:
思路:利用并查集,依次将不属于一个集合中的可能边加入,形成最小生成树,在这之前先按照边权大小排序,贪心优先选择较小的边加入,即可得到最小生成树。
代码:
#include <bits/stdc++.h> #define int long long using namespace std; const int MAXN=500500; int par[MAXN]; int rankk[MAXN]; int n,m; struct node { int u,v,w; }edge[MAXN]; void init() { for(int i=1;i<=n;i++) { par[i]=i; rankk[i]=0; } } int find(int x) { if(x==par[x]) return x; else { return par[x]=find(par[x]); } } void unite(int u,int v) { int du=find(u); int dv=find(v); if(du==dv) return; if(rankk[du]<rankk[dv]) par[du]=dv; else { par[dv]=du; if(rankk[du]==rankk[dv]) rankk[du]++; } } bool cmp(const node &a,const node &b) { return a.w<b.w; } int kruskal() { int res=0; init(); sort(edge+1,edge+1+m,cmp); for(int i=1;i<=m;i++) { if(find(edge[i].u)!=find(edge[i].v)) { unite(edge[i].u,edge[i].v); res=res+edge[i].w; } } return res; } signed main() { scanf("%lld%lld",&n,&m); for(int i=1;i<=m;i++) { scanf("%lld%lld%lld",&edge[i].u,&edge[i].v,&edge[i].w); } printf("%lld\n",kruskal()); }
E题:
思路:只是修改函数部分好像不行,加一个数组进行暴力,纳入一条边的时候把这个区间对应位置的数组值均+1,删除一条边的时候均-1,由于某位置重复出现多次的时候只算一个,所以选择a[i]==1时将ans++,位置从有到无的时候才会-1,所以选择a[i]==0时ans--,比原代码的修改之处就是加了个a[]数组和修改了结构体node的大小比较方式。
代码:
#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 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; struct node { int l,r; bool operator < (const node &other) const { if(l==other.l) return r<other.r; return l < other.l; } }; std::set<node> L; int a[MAXN]; int ans=0; int main(){ scanf("%d%d",&N,&maxL); while(N--){ int opt,x,y; scanf("%d%d%d",&opt,&x,&y); if(opt == 1){ if(L.find((node){x,y}) != L.end()) continue; L.insert((node){x,y}); for(int i=x;i<=y;i++) { a[i]++; if(a[i]==1) ans++; } } if(opt == 2){ if(L.find((node){x,y}) == L.end()) continue; L.erase((node){x,y}); for(int i=x;i<=y;i++) { a[i]--; if(a[i]==0) ans--; } } if(opt == 3){ printf("%d\n",ans); } } return 0; }