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