武汉科技大学第十一届程序设计校赛(周赛训练)
题解报告
题解顺序不是原来比赛的题目顺序
比赛链接
基本的一些理解和问题都在注释中
题目一:杰哥的最小和
如果A和B的最大公倍数为N,则有:
\[N=A\times B\div GCD(A,B)
\]
可以将上述化为:
\[N=(A\div GCD(A,B))\times B=>N=C\times B
\]
如果\(GCD(A,B)\)不等于1的话,那么一定存在一个比A或B更小的C使得\(GCD(C,B)\) 或 \(GCD(A,C)\)为1,而恰好这样得到的\(B+C\)或者\(C+B\)才最小,所以要让\(GCD(A,B)\)为1,才可以得到嘴下,那么可以将N进行质因数分解,然后将N的质因数分成两份集合,相同的质因数要再一个集合,然后枚举集合就行了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int gcd(int x,int y)
{
return y?gcd(y,x%y):x;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--)
{
int N;cin>>N;
int res=N+1;
for(int i=2;i<N/i;i++)//选择集合,直接枚举
if(N%i==0&&gcd(i,N/i)==1)//这里的GCD(i,N/i)==1就代表没有相同的质因数再不同A和B中。
res=min(res,i+N/i);
cout<<res<<endl;
}
return 0;
}
题目二:杰哥的树
进行状态压缩,然后统计不同状态个数后利用组合数学的知识求解就行了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int maxn=2e5+10;
int head[maxn],ver[maxn],nxt[maxn],edge[maxn],tot;
ll state[maxn];
void dfs(int now,int fa,int st)//从开头这里进行搜索。
{
for(int i=head[now];~i;i=nxt[i])
{
int v=edge[i];
if(v==fa)continue;
state[st^(1<<ver[i])]++;
dfs(v,now,st^(1<<ver[i]));
}
}
void addEdge(int u,int v,int w)
{
edge[tot]=v;
ver[tot]=w-'a';
nxt[tot]=head[u];
head[u]=tot++;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
memset(head,-1,sizeof(head));
int N;cin>>N;
for(int i=0;i<N-1;i++)
{
int u,v;char w;
cin>>u>>v>>w;
addEdge(u,v,(int)w);
addEdge(v,u,(int)w);
}
state[0]=1;
dfs(1,0,0);
ll res=0;
for(int i=0;i<maxn;i++)res+=(state[i]*(state[i]-1))/2;
cout<<res<<endl;
return 0;
}
题目三:杰哥,你带我走吧!杰哥
预处理加树上差分就行了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int MOD=1e9+7;
const int maxn=2e5+10;
int edge[maxn],head[maxn],nxt[maxn],tot;
ll num[60][maxn];//前面为多少次方
ll sum[60][maxn];
int fa[maxn][40];//2的多少倍祖先
int deep[maxn];
int N,M;
void addEdge(int u,int v)
{
edge[tot]=v;
nxt[tot]=head[u];
head[u]=tot++;
}
void dfs(int u,int ft,int dep)
{
fa[u][0]=ft;
deep[u]=dep;
for(int i=2;i<=50;i++)num[i][u]=(num[i-1][u]*num[1][u])%MOD;
for(int i=1;i<=50;i++)sum[i][u]=(num[i][u]+sum[i][ft])%MOD;
for(int i=head[u];~i;i=nxt[i])
{
int v=edge[i];
if(v==ft)continue;
dfs(v,u,dep+1);
}
}
void init()
{
for(int i=1;i<35;i++)
for(int j=1;j<=N;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
int LCA(int u,int v)
{
if(deep[u]<deep[v])swap(u,v);
for(int i=30;i>=0;i--)
{
if(deep[fa[u][i]]>=deep[v])
u=fa[u][i];
}
if(u==v)return v;
for(int i=30;i>=0;i--)
{
if(fa[u][i]!=fa[v][i])
{
u=fa[u][i];
v=fa[v][i];
}
}
return fa[u][0];
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
memset(head,-1,sizeof(head));
cin>>N>>M;
for(int i=1;i<=N;i++)cin>>num[1][i];
for(int i=1;i<N;i++)
{
int u,v;cin>>u>>v;
addEdge(u,v);
addEdge(v,u);
}
dfs(1,0,1);
init();
for(int i=0;i<M;i++)
{
int u,v,k;cin>>u>>v>>k;
int ft=LCA(u,v);
cout<<(sum[k][u]+sum[k][v]-sum[k][ft]-sum[k][fa[ft][0]]+2*MOD)%MOD<<endl;
}
return 0;
}
题目四:杰哥的集合
并查集模拟,注意一下合成的方式就行了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <unordered_map>
using namespace std;
const int maxn=1e5+10;
vector<int> number[maxn];
unordered_map<int,int> nums[maxn];
int fa[maxn],MAX[maxn];
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx==fy)return;//注意这里要写,避免重复计算
if(number[fy].size()<number[fx].size())swap(fx,fy);//这里要每次都是大的和小的,保证O(n)
int len=number[fx].size();
for(int i=0;i<len;i++)
{
number[fy].push_back(number[fx][i]);
nums[fy][number[fx][i]]++;
if(nums[fy][number[fx][i]]>nums[fy][MAX[fy]]||(nums[fy][number[fx][i]]==nums[fy][MAX[fy]]&&number[fx][i]<MAX[fy]))MAX[fy]=number[fx][i];
}
number[fx].clear();
nums[fx].clear();
fa[fx]=fy;
}
void init(int N)
{
for(int i=1;i<=N;i++)fa[i]=i;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int N,M;cin>>N>>M;
init(N);
for(int i=1;i<=N;i++)
{
int x;cin>>x;
number[i].push_back(x);
nums[i][x]++;MAX[i]=x;
}
for(int i=0;i<M;i++)
{
int OP;cin>>OP;
if(OP==1){
int x,y;cin>>x>>y;
merge(x,y);
}else{
int x;cin>>x;
cout<<MAX[find(x)]<<endl;
}
}
return 0;
}
题目五:杰哥闯稻妻
BFS或者DFS搜索就行
注意一下状态压缩的方法
#include <cstdio>//由于题目限制了步数,且状态较少,所以使用bfs可以很快找到答案。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e4+10;
int End=3+(3<<2)+(3<<4)+(3<<6)+(3<<8);
struct node
{
int st;
string s;
}state[maxn];
int vis[maxn];
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
queue<node>q;
int state=0;
for(int i=0;i<5;i++)
{
int x;cin>>x;
state+=((x-1)<<(i*2));
}
q.push({state,""});
while(!q.empty())
{
node now=q.front();q.pop();
if(vis[now.st])continue;
vis[now.st]=1;
if(now.st==End)
{
cout<<now.s.size()<<endl;
int len=now.s.size();
for(int i=0;i<len;i++)cout<<now.s[i]<<' ';
break;
}
for(int i=0;i<5;i++)
{
int Newstate=now.st;
for(int j=-1;j<=1;j++)
{
//这里的状态压缩记一下,方便以后直接进行压缩。
int pos=(i+j+5)%5;//这里的括号要限制好,不要忘了。
Newstate=((Newstate+(1<<(pos*2)))&(3<<(pos*2)))+(Newstate&(~(3<<(pos*2))));
}
q.push({Newstate,now.s+(char)(i+'1')});
}
}
return 0;
}
题目六:杰哥哄对象
注意状态的转移,当前状态可以由什么状态转移而来
注意一个字符可以进行的各种操作,或者不只是一个字符,一个状态可以由两个或多个字符的变换来确定。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1e7+10;
int dp[maxn];
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
string s;cin>>s;
int len=s.size();
s="0"+s;dp[1]=1;
for(int i=2;i<=len;i++)
{//每次以两个为判断,不牵扯别的完美字符串。
dp[i]=dp[i-1]+1;//删去自己
dp[i]=min(dp[i],dp[i-2]+(s[i]!=s[i-1]));//更换自己或者上一个
if(i>=3&&s[i]==s[i-2])dp[i]=min(dp[i],dp[i-3]+1);//删去上一个
//通过这三步操作一定是最小的,因为不可能一次删去两个,只能每次都这么选,删去两个需要的操作量较大。
}
cout<<dp[len]<<endl;
return 0;
}
题目七:杰哥抓气球
注意一下原点可能有气球就行
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;cin>>T;
int ans=0;
while(T--)
{
int X,Y;cin>>X>>Y;
if(!X&&!Y)continue;
int Temp=X*X+Y*Y;
int Int=(int)sqrt(Temp);
if(Temp==Int*Int)ans+=2;
else ans+=4;
}
cout<<ans<<endl;
return 0;
}
至于这场比赛其它的题目视乎都是我力所不能及的,就不补了
作者:WUTONGHUA02
-------------------------------------------
个性签名:啊啊啊,敲代码真的是太难了!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
努力努力,再努力,哈哈哈(っ•̀ω•́)っ✎⁾⁾!