东华大学2020年程序设计竞赛(同步赛)B题+C题

B-A Number Theoretical Problem

传送门
题意:给定一个正整数y和一个素数p,找到一个整数x满足x*y%p==1,输出x%p,注意x%p是非负的
思路1:逆元解法
先来推一波公式:

在这里插入图片描述
Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll qpow(ll a,ll k,ll p){
    ll res=1;
    while(k){
        if(k&1) res=res*a%p;
        a=a*a%p;
        k>>=1;
    }
    return res;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        int y,p;scanf("%d%d",&y,&p);
        if(y%p==0) puts("-1");   ///这种情况找不到任何的x,直接输出-1
        else{   ///套用上面的结论,逆元求解
            ll infact=qpow(y,p-2,p);
            printf("%lld\n",infact%p);
        }
    }
    return 0;
}

思路二:扩展欧几里得(线性同余方程)
也是先来做一波等价变换:
在这里插入图片描述
Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll exgcd(ll a,ll b,ll &x,ll &y){   ///扩展欧几里得
    if(!b){
        x=1,y=0;
        return a;
    }
    ll d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        ll a,p;scanf("%lld%lld",&a,&p);
        ll x,y;
        ll d=exgcd(a,p,x,y);
        if(1%d) puts("-1");   ///1%d!=0表示无解
        else printf("%lld\n",((x*(1/d)%p)+p)%p);   ///因为此题需要输出一个正整数,求的x有可能是负的,输出时处理一下就好了
    }
    return 0;
}

C-City Supplies

传送门
题意:给定n和m,抽象成图的话,就是n个节点和m条无向边,要求求出每个节点到1号节点的最小距离,然后再求1号节点到每个点的代价,根据题意,后面就是个快速幂
这题真是坑,赛前赛后一共交了62次,这锅真的不想背
思路一:bfs
因为此题边权是1嘛,bfs也是可以解决的,所有的节点只会被更新一次,先遍历到比后遍历到一定距离更短;用一个队列来维护已经更新过的点,用这些点再更新这些点的邻点,这里不需要标记数组,将距离数组初始化为-1就ok,题目已经保证了图是一定连通的
Code:

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<stack>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
const int maxn = 4e6 + 10;
const int mod = 1e9+7;
typedef long long ll;
typedef unsigned long long ull;
int n,m;
int e[maxn],ne[maxn],h[maxn],idx;
int dist[maxn];
ll qpow[maxn];
bool vis[maxn];
inline ll read() {
    ll c = getchar(), Nig = 1, x = 0;
    while (!isdigit(c) && c != '-')c = getchar();
    if (c == '-')Nig = -1, c = getchar();
    while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
    return Nig * x;
}
ll quick_pow(ll a,ll k){
    ll res=1;
    while(k){
        if(k&1) res=(res*a)%mod;
        a=(a*a)%mod;
        k>>=1;
    }
    return res;
}
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs(){
    memset(dist,-1,sizeof dist);
    dist[1]=0;
    int hh=1,tt=1;
    int q[maxn];
    q[1]=1;
    while(hh<=tt){
        int t=q[hh++];
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]==-1)   ///此节点还没有被更新
            {
                dist[j]=dist[t]+1;
                q[++tt]=j;   ///将节点加入队列
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    n=read();
    m=read();
    memset(h,-1,sizeof h);
    qpow[1]=2;
    ///for(int i=2;i<=n;i++) qpow[i]=qpow[i-1]*2%mod;   ///打表
    for(int i=1;i<=m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        a=read();
        b=read();
        add(a,b);   ///存边
        add(b,a);
    }
    bfs();
    ll sum=0;
    for(int i=2;i<=n;i++)
    {
        ///sum=(sum+qpow[dist[i]])%mod;   ///打表
        sum=(sum+quick_pow(2,dist[i]))%mod;   ///快速幂   两种求答案方式都可
    }
    printf("%lld\n",sum);
    return 0;
}

思路二:dijkstra(堆优化)
求每个点的最短路径基于贪心的基础,每次遍历会确定一个节点的最短路径,并将其放入堆并打上标记,再遇到这点直接略过,用这点去更新其他相邻的点,n次遍历会确定n个节点到达1号节点的最短路径,他的前提是没有负权边,本题也满足
Code:

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<stack>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
const int maxn = 4e6 + 10;
const int mod = 1e9+7;
typedef long long ll;
typedef unsigned long long ull;
int n,m;
ll qpow[maxn];
typedef pair<int,int> PII;
int e[maxn],ne[maxn],h[maxn],idx,w[maxn];
int dist[maxn];
bool vis[maxn];
inline ll read() {
    ll c = getchar(), Nig = 1, x = 0;
    while (!isdigit(c) && c != '-')c = getchar();
    if (c == '-')Nig = -1, c = getchar();
    while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
    return Nig * x;
}
void add(int a,int b,int c){
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
ll quick_pow(ll a,ll k){
    ll res=1;
    while(k){
        if(k&1) res=(res*a)%mod;
        a=(a*a)%mod;
        k>>=1;
    }
    return res;
}
void dijkstra(){
    memset(dist,0x3f,sizeof dist);   ///初始化为正无穷
    priority_queue<PII,vector<PII>,greater<PII> > heap;   ///堆中需要存储两个元素,距离和节点
    dist[1]=0;
    heap.push({0,1});
    while(heap.size()){
        PII t=heap.top();
        heap.pop();
        int jiedian=t.second,distance=t.first;
        if(!vis[jiedian])
        {
            vis[jiedian]=true;
            for(ll i=h[jiedian];i!=-1;i=ne[i])
            {
                int j=e[i];
                if(dist[j]>distance+w[i])
                {
                    dist[j]=distance+w[i];
                    heap.push({dist[j],j});
                }
            }
        }
    }
}
int main(){
    memset(h,-1,sizeof h);
    n=read();
    m=read();
    qpow[1]=2;
    ///for(int i=2;i<=n;i++) qpow[i]=qpow[i-1]*2%mod;
    for(int i=1;i<=m;i++){
        int a,b;
        a=read();
        b=read();
        add(a,b,1);
        add(b,a,1);
    }
    dijkstra();
    ll sum=0;
    for(int i=2;i<=n;i++)
    {
    	///sum=(sum+qpow[dist[i]])%mod;   ///打表
        sum=(sum+quick_pow(2,dist[i]))%mod;   ///快速幂
    }
    printf("%lld\n",sum);
    return 0;
}

没有太晚的开始,不如就从今天行动。总有一天,那个一点一点可见的未来,会在你心里,也在你的脚下慢慢清透。生活,从不亏待每一个努力向上的人。

猜你喜欢

转载自blog.csdn.net/zhazhaxiaosong/article/details/106608506
今日推荐