2021牛客寒假算法基础集训营6

链接:https://ac.nowcoder.com/acm/contest/9986

A 回文括号序列计数 | 坑,理解题意

【题意】
求长度为n的回文括号序列的方案数。
【范围】
样例组数T<=1000000
0<=n<=10^9
【思路】
()的回文是)(,因此只有n=0时为1,其余全为0

ll n;
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        cin>>n;
        if(n==0)cout<<1<<endl;
        else cout<<0<<endl;
    }
}

C 末三位 | 签到

【题意】
5 n 5^n 5n的末三位
【范围】
样例组数T<=10^6
0<=n<=10^9
【思路】
n>=3后是“125”和“625”循环

ll n;
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    while(cin>>n){
        if(n==0)cout<<"001"<<endl;
        else if(n==1)cout<<"005"<<endl;
        else if(n==2)cout<<"025"<<endl;
        else if(n%2)cout<<"125"<<endl;
        else cout<<"625"<<endl;
    }
}

D 划数 | 思维

【题意】
n个数,每次删去其中任意两个,加上这两个数的和对11取模的值。
只剩两个数时,一个为cnt,求另一个。
【范围】
2 <= n <= 150000, 1 <= num[i] <= 1e6, cnt>=11
数据组数T<=10
【思路】
剩下的cnt一定是没删过的

ll n,cnt;
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    while(cin>>n>>cnt){
        ll x,res;cin>>res;
        if(res==cnt)res=0;
        res%=11;
        for(int i=1;i<n;i++){
            cin>>x;
            if(x==cnt)continue;
            res+=x;res%=11;
        }
        cout<<res<<endl;
    }
}

F 组合数问题 | 数学

【题意】
求C(n,0)+C(n,4)+C(n,8)+…+C(n,n),n是4的倍数,答案对998244353取模
【范围】
1<=n<=1e18
【思路】
考虑到n那么大,因此复杂度应该不能超过O(logn),需要推出数学表达式。
对于C(n,0)+C(n,2)+C(n,4)+…+C(n,n),可以用(x+y)^n二项式展开得出
所以在比赛的时候,就想能不能用虚数构造,但又不会算(1+i)^n这种式子
然后就想找规律,发现n=12时,res=992=210-25,就想到2n-2-2(n-2)/2,但又发现n=16时候不对(其实就差个-1)
最后就是OEIS得出结果,再化简一下
2n-2+(-1)n/4·2(n-2)/2

const ll mod=998244353;
ll n,res;
ll qpow(ll a, ll b)
{
    ll t = a,ans = 1;
    while(b)
    {
        if (b & 1) ans =ans * t%mod;
        t = t*t %mod;
        b>>=1;
    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n;
    res=qpow(2,n-2);
    if((n/4)%2){
        res+=mod;
        res-=qpow(2,n/2-1);
        res%=mod;
    }
    else{
        res+=qpow(2,n/2-1);
        res%=mod;
    }
    cout<<res<<endl;
}

【赛后】
两种推导:
1、虚数
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=46862263
在这里插入图片描述
2、两个公式化简:
在这里插入图片描述


G 机器人 | (贪心/状压dp)+高精度

【题意】
有 n 个机器人,每个机器人会读入一个 x ,并返回 ax+b 。
有一个数 x ,将机器人按某种顺序排列,使得最终返回得到的 x 尽可能大。
【范围】
1<=n,x, a i a_{i} ai, b i b_{i} bi<=20
【思路】
贪心:
在这里插入图片描述
排序,比较 a 2 a_{2} a2 b 1 b_{1} b1+ b 2 b_{2} b2 a 1 a_{1} a1 b 2 b_{2} b2+ b 1 b_{1} b1
又因为数据较大,会爆long long,因此需要高精或__int128(不会用,就抄了个高精板子)

/*此处省略高精板子*/
struct node{
    Wint a,b;
};
vector<node> vec;
Wint n,x;
bool cmp(node n1,node n2){
    return n1.a*n2.b+n1.b<n2.a*n1.b+n2.b;
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>x;
    for(int i=1;i<=n;i++){
        Wint p,q;cin>>p>>q;
        vec.pb(node{p,q});
    }
    sort(vec.begin(),vec.end(),cmp);
    for(int i=0;i<n;i++){
        x*=vec[i].a;
        x+=vec[i].b;
    }
    cout<<x;
}

【赛后】
这题还可以状压dp
在这里插入图片描述


I 贪吃蛇 | 宽搜

【题意】
n*m的迷宫,’#‘不可走,’.'可走,且走过的点格子不能再走,求起点S和终点E之间的最短距离。
【范围】
1<=n,m<=100
【思路】
简单的bfs

int n,m,xs,ys,xe,ye;
char a[105][105];
int vis[105][105];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
bool check(int x,int y){
    if(!vis[x][y]&&a[x][y]=='.')return 1;
    return 0;
}
int bfs(){
    queue<P> q;
    q.push(P(xs,ys));
    vis[xs][ys]=1;
    int cnt=0;
    while(!q.empty()){
        int sz=q.size();
        while(sz--){
            P p=q.front();q.pop();
            if(p.first==xe&&p.second==ye)return cnt;
            for(int i=0;i<4;i++){
                int a=p.first,b=p.second;
                if(check(a+dx[i],b+dy[i])){
                    vis[a+dx[i]][b+dy[i]]=1;
                    q.push(P(a+dx[i],b+dy[i]));
                }
            }
        }
        cnt++;
        if(q.empty())return -1;

    }return cnt;
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m>>xs>>ys>>xe>>ye;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    int x=bfs();
    if(x==-1)cout<<-1<<endl;
    else cout<<x*100<<endl;
}


J 天空之城 | 最小生成树kruskal

【题意】
有n个城市,用字符串表示,q条有权边,求从一个城市出发,走遍所有城市的最短路径,走过的路径再走不用花费时间。
【范围】
在这里插入图片描述

【思路】
明显是最小生成树,但开始却没想到。。还是太不熟悉这个数据结构了,虽然之前看过,离散数学也学过,但没实际解题用过。
还因为没输出"NO",wa了几发。。。

ll n,m,tot=0,k=0;//n端点总数,m边数,tot记录最终答案,k已经连接了多少边
ll fat[200010];//记录集体老大
struct node
{
	int from,to,dis;//结构体储存边
}edge[200010];
bool cmp(const node &a,const node &b)//sort排序(当然你也可以快排)
{
	return a.dis<b.dis;
}
int father(int x)//找集体老大,并查集的一部分
{
	if(fat[x]!=x)
	return father(fat[x]);
	else return x;
}
void unionn(int x,int y)//加入团体,并查集的一部分
{
	fat[father(y)]=father(x);
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    while(cin>>n>>m){
        tot=0;k=0;
        memset(fat,0,sizeof(fat));
        string ss;cin>>ss;
        map<string,ll> mp;
        ll cnt=1;
        for(int i=1;i<=m;i++){
            string s1,s2;
            ll t;
            cin>>s1>>s2>>t;
            if(!mp.count(s1))mp[s1]=cnt++;
            if(!mp.count(s2))mp[s2]=cnt++;
            edge[i].from=mp[s1];
            edge[i].to=mp[s2];
            edge[i].dis=t;
        }
        for(int i=1;i<=n;i++) fat[i]=i;
        sort(edge+1,edge+1+m,cmp);
        for(int i=1;i<=m;i++)
        {
            if(k==n-1) break;
            if(father(edge[i].from)!=father(edge[i].to))
            {
                unionn(edge[i].from,edge[i].to);
                tot+=edge[i].dis;
                k++;
            }
        }
        if(k!=n-1)cout<<"No!"<<endl;
        else cout<<tot<<endl;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

General.song

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值