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;
}


京公网安备 11010502036488号