每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

AtCoder Beginner Contest 293(C,D ,E,F)

AtCoder Beginner Contest 293(C,D ,E,F)

C

C

这道题其实还蛮好写的,就是一个dfs,然后我看错了题意,就记录一下

这道题的大意是我们需要从(1,1)走到(n,m),我们只有两种走法,向下走和向右走,然后对于这一条路上存在有两个位置上的数是一样的,那么我们就认为这一条路是不高兴的,问我们从(1,1)走到(n,m)高兴的路有多少条

题意理解清楚了就很好办

对于判断是否高兴,我们可以用到回溯

然后又看到nm都不是很大,那么我们就可以直接dfs

#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
#define int long long 
const int maxn=2e5+10;
int n,m;
int a[20][20];
map<int,bool>vis;
int ans;
void dfs(int x,int y)
{
    if(x==n&&y==m) 
    {
       ans++;
       return ;
    }
    int sum=0;
    if(x<n)
    {
        if(!vis[a[x+1][y]])
        {
            vis[a[x+1][y]]=true;
             dfs(x+1,y);
            vis[a[x+1][y]]=false;
        }
    }
    if(y<m)
    {
        if(!vis[a[x][y+1]])
        {
            vis[a[x][y+1]]=true;
            dfs(x,y+1);
            vis[a[x][y+1]]=false;
        }
    }
    return ;
}
signed  main ()
{
    cin>>n>>m;
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    vis[a[1][1]]=true;
    ans=0;
      dfs(1,1);
     cout<<ans<<'\n';
    system ("pause");
    return 0;
}

D

D

我一看这题就迷糊

什么颜色,什么捆绑,讲的迷迷糊糊的,看的我太气愤了

然后看了佬们的题解才真正的看懂这个题意

其实这个题目有一个干扰条件,就是那个颜色

我们在做题的时候可以不用管那个颜色,然后会有m次捆绑两条绳子,问最后有多少个绳子集合是有环的,有多少个绳子集合是无环的

对于捆绑合并这一类的问题,我们可以用并查集

然后对于这一个集合,怎样判断这一个集合里面是否存在环呢

我们可以想到对于n个点,要使这n个点没有环并且边最多的时候边的数量为n1

那么对于存在cnt个点的集合,如果这cnt个点里面的边的数量大于等于点的数量,那么就说明这个集合一定有环,否则无环

#include <iostream>
#include <string>
using namespace std;
const int maxn=2e5+10;
int f[maxn],siz[maxn],d[maxn];
int n,m;
int find(int x)
{
    if(x==f[x]) return x;
    return f[x]=find(f[x]);
}
void merge(int x,int y)
{
    int tx=find(x);
    int ty=find(y);
    if(tx==ty) return ;
    f[ty]=tx;
    siz[tx]+=siz[ty];
    d[tx]+=d[ty];
    siz[ty]=0;
}
int main ()
{
    cin>>n>>m;
    for (int i=1;i<=n;i++)//记得要初始化
    {
        f[i]=i;
        siz[i]=1,d[i]=0;
    }
    for (int i=1;i<=m;i++)
    {
        char ch1,ch2;
        int u,v;
        cin>>u>>ch1>>v>>ch2;
        merge(u,v);
        d[find(u)]++;//还要记u,v之间还有一条边是连接这两个点的
    }
    int cnt1=0,cnt2=0;
    for (int i=1;i<=n;i++)
    {
        if (i==find(i))
        {
            if(d[i]>=siz[i])
            {
                cnt1++;
            }
            else cnt2++;
        }
    }
    cout<<cnt1<<" "<<cnt2<<"\n";
    system ("pause");
    return 0;
}

E

E

我们要求以下式子的和

i=0x1ai

那么我们就可以把这些看成是一个等比公式,公比是a

可以变化成

a0+a1+a2+...+ax2+ax1

那么我们对于这一个式子,我们还可以进行以下两种变换

如果x是一个偶数,那么就相当于这一个式子可以分成两部分

如下

i=0x1ai=(a0+a1+...ax21)+ax2×(a0+a1+...ax21)

而如果x是一个奇数,那么可以进行以下变换

i=0x1ai=a0+a×(a0+a1+a2+...+ax2)

我们可以发现,x不管是奇数还是偶数,都会进入下一个更小的求和,所以我们就可以发现其中的规律

然后我们就可以推断出递推的公式了

int get(int x)
{
    if(x==1) return 1;
    if(x&1)
    {
        return ((1+a*get(x-1)%mod)%mod);
    }
    else 
    {
        return (((ksm(a,x/2)+1)%mod*get(x/2))%mod);
    }
}

具体操作就看代码

#include <iostream>
#include <algorithm>
using namespace std;
#define int long long 
int mod;
int a,x;
int ksm(int x,int p)
{
    int res=1;
    while (p)
    {
        if(p&1)
        {
            res=(res*x)%mod;
        }
        x=(x*x)%mod;
        p>>=1;
    }
    return res%mod;
}
int get(int x)
{
    if(x==1) return 1;
    if(x&1)
    {
        return ((1+a*get(x-1)%mod)%mod);
    }
    else 
    {
        return (((ksm(a,x/2)+1)%mod*get(x/2))%mod);
    }
}
signed main ()
{
    cin>>a>>x>>mod;
    int ans=get(x);
    ans%=mod;
    cout<<ans<<'\n';
    system ("pause");
    return 0;
}

F

F

这个题意虽然一开始没看懂,但最后还是看懂了

大意就是给你一个数n,问有多少种进制可以表示出n

62进制可以是110,用5进制可以是11这种的表达形式

我们可以知道这个进制一定是小于等于n里面寻找的

然后我们可以注意到这个n非常的大,那么我们可以分成两部分

对于小于等于1000的我们可以直接判断

对于怎么判断一个数是否可以用这样的进制表达

我们是这样子判断的

bool check(int x)
{
    int now=n;
    while (now)
    {
        if(now%x>1) return false;
        now/=x;
    }
    return true;
}

对于大于1000的,要到达1e18,最多就是6位,这就以为着这里面的形式(1100这种的)不是很多,我们可以考虑列举出这些形式,找到一个合适的进制,看是否可以得到n

对于每一种形式怎么找到一个合适的进制呢

我们可以用二分来查找

__int128 calc(int bit,int v)//这里用到了__int128,用long long 可能不够
{
    __int128 s=0,pw=1;
    for (int j=0;j<7;j++)
    {
        if(bit>>j&1)
        {
            if(pw>n) return 9e18;
            else 
            {
                s+=pw;
            }
        }
        if(s>n) return 9e18;
        if(pw<2e18)
        {
            pw*=v;
        }
    }
    return s;
}

我觉得这道题比较好的点就是他对于一个很大的数,它对于那些可能进制数很大的它不是一个一个直接判断,而是通过我们还可以存在的形式来找那些进制(最多只有271个)

然后这个题还要注意数据的范围,有些地方可能会超过long long

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define int long long 
int t,n;
bool check(int x)
{
    int now=n;
    while (now)
    {
        if(now%x>1) return false;
        now/=x;
    }
    return true;
}
__int128 calc(int bit,int v)
{
    __int128 s=0,pw=1;
    for (int j=0;j<7;j++)
    {
        if(bit>>j&1)
        {
            if(pw>n) return 9e18;
            else 
            {
                s+=pw;
            }
        }
        if(s>n) return 9e18;
        if(pw<2e18)
        {
            pw*=v;
        }
    }
    return s;
}
bool binarysearch(int bit)
{
    __int128 l=1001,r=2e18;
    __int128 ans;
    while (l<=r)
    {
        __int128 mid=(l+r)>>1;
        if(calc(bit,mid)<=n)
        {
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    if(calc(bit,ans)==n) return true;
    else return false;
}
void solve()
{
    cin>>n;
    int ans=0;
    for (int i=2;i<=min(n,1000*1ll);i++)
    {
        ans+=check(i);
    }
    if(n>1000)
    {
        for (int state=1;state<(1<<7);state++)
        {
            ans+=binarysearch(state);
        }
    }
    cout<<ans<<'\n';
    return ;
}
signed main ()
{
    cin>>t;
    while (t--)
    {
        solve();
    }
    system ("pause");
    return 0;
}

posted @   righting  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示