Hello,大家好!
我是蒟亦先生!
温馨提示:请各位奆奆们洁身自好,请勿COPY!
题解:
unimodal
代码实现+解析
我们根据数据其实不难得出,
n的全排列中单峰排列的个数为2的n-1次方,
所以可以用快速幂解决
更严谨的说法:
f(1)=1;
f(2)=2;
对于f(n),n可以放在n-1的任意组合
且只能放在n-1的前面或后面
故f(n)=f(n-1)*2;
f(n)=2的n-1次方
#include<bits/stdc++.h>
using namespace std;
long long n,i,j;
long long pqow(long long a,long long b)//快速幂
{
long long sx=a,ans=1;
while(b!=0)
{
if(b&1!=0)
{
ans*=sx;
ans%=1234567;
}
sx*=sx;
sx%=1234567;
b/=2;
}
return ans%1234567;
}
int main()
{
cin>>n;
n--;
cout<<pqow(2,n);
return 0;
}
grid
代码实现+解析
本题的思路很简单:并查集+最小生成树 优先考虑纵向,再不行连接横向 一共需要三次并查集操作 (详情请看代码)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+1;
long long n,m,f[maxn],x,y,x2,y2,ans,i,j;
long long find(long long z)
{
return f[z]==z?z:f[z]=find(f[z]);
}
int main()
{
cin>>n>>m;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
f[m*(i-1)+j]=m*(i-1)+j;
}
}
while(cin>>x>>y>>x2>>y2)
{
int k1=find(m*(x-1)+y),k2=find(m*(x2-1)+y2);//第一次
if(k1!=k2)
{
f[k1]=k2;
}
}
for(i=1;i<=m;i++)//优先纵向,边权为1
{
for(j=1;j<n;j++)
{
int k1=find(m*(j-1)+i),k2=find(m*j+i);//第二次
if(k1!=k2)
{
ans++;
f[k1]=k2;
}
}
}
for(i=1;i<=n;i++)//纵向连不完,再连接横向,边权为2
{
for(j=1;j<m;j++)
{
int k1=find(m*(i-1)+j),k2=find(m*(i-1)+j+1);//第3次
if(k1!=k2)
{
ans+=2;
f[k1]=k2;
}
}
}
cout<<ans;
return 0;
}
pair
代码实现+解析
把关系看做边,问题转化求一条边不重复的路径,即欧拉路径。
先判断有没有连通性和两个奇点
接着循环寻找与x相连的边(x,u)——删边
然后将x插入栈中
这样可以保证找到的一定是字典序最小的合法方案
#include<bits/stdc++.h>
using namespace std;
const int maxn=500;
int n,st,cnt,bz,d[maxn],f[maxn],a[maxn][maxn];
char ans[maxn];
int find(int z)
{
return f[z]==z?z:f[z]=find(f[z]);
}
void dfs(int x)
{
for(int i=1;i<=maxn;i++)
{
if(a[x][i])
{
a[x][i]=a[i][x]=0;
dfs(i);
}
}
ans[n--]=x;
}
int main()
{
int i,j;
scanf("%lld",&n);
for(i=1;i<=maxn;i++)
{
f[i]=i;
}
for(i=1;i<=n;i++)
{
char ch[3];
scanf("%s",ch);
int x=ch[0],y=ch[1];
a[x][y]=a[y][x]=1;
d[x]++;
d[y]++;
f[find(x)]=find(y);
}
for(i=1;i<=maxn;i++)//判断连通性
{
if(f[i]==i&&d[i])
{
bz++;
}
}
if(bz!=1)
{
printf("No Solution");
return 0;
}
for(i=1;i<=maxn;i++)//判奇点(为链)
{
if(d[i]&1)
{
cnt++;
if(!st)
{
st=i;
}
}
}
if(cnt&&cnt!=2)
{
printf("No Solution");
return 0;
}
if(!st)//判环,找到最小点
{
for(i=0;i<maxn;i++)
{
if(d[i])
{
st=i;
break;
}
}
}
dfs(st);
printf("%s",ans);
return 0;
}
transfer
代码实现+解析
本题看上去是一道数论题,实际上是一个图论题。
题目要求——
每个点可以转换成约数和的条件是和大小小于当前的数。
所以每个点要么可以向前变,要么没有向前变。
如果以约数为根,那么就得到许多的树,
也就是说,他们是一些森林,约数和是父亲。
然后求最长的变换距离(最长连),做一个DP即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=55555;
long long n,ans,i,j,sum[maxn],dis1[maxn],dis2[maxn];
int main()
{
cin>>n;
for(i=1;i<=n;i++)
{
for(j=2;i*j<=n;j++)
{
sum[i*j]+=i;
}
}
for(i=n;i>=1;i--)
{
j=sum[i];
if(j<i)
{
if(dis1[i]+1>dis1[j])
{
dis2[j]=dis1[j];
dis1[j]=dis1[i]+1;
}
else if(dis1[i]+1>dis2[j])
{
dis2[j]=dis1[i]+1;
}
}
}
for(i=1;i<=n;i++)
{
ans=max(ans,dis1[i]+dis2[i]);
}
cout<<ans;
return 0;
}
谢谢各位奆奆!
题解制作不易,望能用心思考
如有疑问,欢迎提出问题一起讨论!