洛谷题(快速幂,分层图,dfs,拓扑)

P3811 【模板】乘法逆元

对于一个数求逆元 这个简单 就是根据费马小定理 快速幂,ksm(i,mod-2,mod); 但是题目要求是求1~n所有的逆元 所以这样超时 所以 必须想一个复杂度低的,对于一个mod来说 可以设为 p=ki+r k是商 r是余数,那么可以进行转换 ,ki+r=0(mod p); 然后两方乘r-1 , i-1 得到i-1=-kr-1 ,i-1=-[P/i](pmod i )-1,所以就能找到逆元了

#include <bits/stdc++.h>
#include <iostream> 
#define int long long 
using namespace std;
const int N=3e6+10,M=5e5+10;
typedef pair<int,int> PII;
const int mod=80112002;
int f[N];
int n,m,p;
signed main(){
    ios::sync_with_stdio(0);
    cout.tie(0);
	cin>>n>>p;
	f[1]=1;
	for(int i=2;i<=n;i++){
		f[i]=(p-p/i)*(f[p%i])%p;
	}
	for(int i=1;i<=n;i++){
	    cout<<f[i]<<'\n';
	}
} 


P4568 [JLOI2011] 飞行路线

分层图的概念 对于一条路线来说 我可以往下走走到下一个图去 然后这条线是不用钱的 就可以通到k个图去 然后对于我们来说就是跑到第k层图的终点需要花的多少钱 然后 对于任何一个图的终点都要连通 这样就不会出错

#include <bits/stdc++.h> 
using namespace std;
#define int long long
typedef pair<int, int> PII;
const int N = 111111,M=2500001;
int n, m,k;
int s,t;
bool st[N];
int h[N],ne[M],e[M],dist[N],w[M],idx;
void add(int a,int b,int c=0){
	e[idx]=b;w[idx]=c;
	ne[idx]=h[a];
	h[a]=idx++;
}

void dijks(){
	memset(dist,0x3f,sizeof dist);
	dist[s]=0;
	priority_queue<PII,vector<PII>,greater<PII>> q;
	q.push({0,s});
	while(q.size()){
		auto t=q.top();q.pop();
		int ver=t.second,d=t.first;
		if(st[ver])continue;
		st[ver]=true;
		for(int i=h[ver];~i;i=ne[i]){
			int j=e[i];
			if(dist[j]>dist[ver]+w[i]){
				dist[j]=dist[ver]+w[i];
				q.push({dist[j],j});
			}
		}
	}
}
signed main() {
	memset(h,-1,sizeof h);
	cin >> n >>m>>k;
	cin>>s>>t;
	while(m--){
		int a,b,c;cin>>a>>b>>c;
		add(a,b,c);
		add(b,a,c);
		for(int i=1;i<=k;i++){
			add(a+(i-1)*n,b+i*n);
			add(b+(i-1)*n,a+i*n);
			add(a+i*n,b+i*n,c);
			add(b+i*n,a+i*n,c);
		}
	}
	for(int i=1;i<=k;i++){
		add(t+(i-1)*n,t+i*n);
	}
	dijks();
	cout<<dist[t+k*n]<<endl;
}

P1106 删数问题

首先会出现前导0的情况 所以不能常规处理 两个方案 一是找到k个前面最小的数 的位置 然后把前面全删了 ,有因为遇到0 那么前面的一定会删掉 0也不会输出 ;

还有另一种方案 就是每次找的时候 找到0 那么就是前面的全删 不存在表里 然后 遇到0就这样 直到 达到删除了那么多个数 过着 这里面的数已经够k个 ,就不用删

#include <bits/stdc++.h>
#define int long long 
using namespace std;
const int N=520;
int n,m,T; 
typedef pair<int,int> PII; 
int a[N];
signed main(){
	string s;cin>>s;cin>>m;
	n=s.size();
	for(int i=1;i<=n;i++){
		a[i]=s[i-1]-'0';
	}
	int t=n-m;
	int cnt=0;
	int j=1;
	bool flag=false;
	while(cnt<t){
		int tt=j;
		for(int k=j;k<=m+j;k++)if(a[tt]>a[k])tt=k;
		if(a[tt])flag=true;
		if(flag)cout<<a[tt];
		m-=tt-j;
		j=tt+1;
		cnt++;
	}
	if(!flag)cout<<0;
} 


最大食物链

dfs 和拓扑排序 都是可以的,需要存一下入度 出度

#include <bits/stdc++.h>
#include <iostream> 
#define int long long 
using namespace std;
const int N=5010,M=5e5+10;
typedef pair<int,int> PII;
const int mod=80112002;
int h[N],e[M],ne[M];
int f[N];
bool st[N];
int in[N];
int ou[N];
int idx;
int n,m;
void add(int a,int b){
	ne[idx]=h[a];
	e[idx]=b;
	h[a]=idx++;
}
void solve(){
	queue<int> q;
	for(int i=1;i<=n;i++){
		if(in[i]==0){
			q.push(i);
			f[i]=1;
		}
	}
	int ans=0;
	while(q.size()){
		int t=q.front();q.pop();
		for(int i=h[t];i!=-1;i=ne[i]){
			int j=e[i];
			--in[j];
			f[j]=(f[j]+f[t])%mod;
			if(in[j]==0)q.push(j);
		}
	}
	for(int i=1;i<=n;i++){
		if(!ou[i]){
			ans=(ans+f[i])%mod;
		}
	}
	cout<<ans<<endl;
}
signed main(){
	cin>>n>>m;
	memset(h,-1,sizeof h);
	while(m--){
		int a,b;cin>>a>>b;
		add(a,b);
		in[b]++;
		ou[a]++;
	}
	solve();
} 
#include <bits/stdc++.h>
#include <iostream> 
#define int long long 
using namespace std;
const int N=5010,M=5e5+10;
typedef pair<int,int> PII;
const int mod=80112002;
int h[N],e[M],ne[M];
int f[N];
bool st[N];
int in[N];
int ou[N];
int idx;
int n,m;
void add(int a,int b){
	ne[idx]=h[a];
	e[idx]=b;
	h[a]=idx++;
}
int dfs(int t){
	if(ou[t]==0)return 1;
	if(f[t])return f[t];
	int ans=0;
	for(int i=h[t];i!=-1;i=ne[i]){
		int j=e[i];
		ans+=dfs(j)%mod;
	}
	return f[t]=ans%mod;
}
void solve(){
	queue<int> q;
	for(int i=1;i<=n;i++){
		if(in[i]==0){
			q.push(i);
		}
	}
	int ans=0;
	while(q.size()){
		int t=q.front();q.pop();
		for(int i=h[t];i!=-1;i=ne[i]){
			int j=e[i];
			ans=(ans+dfs(j)%mod)%mod;
		}
	}
	cout<<ans<<endl;
}
signed main(){
	cin>>n>>m;
	memset(h,-1,sizeof h);
	while(m--){
		int a,b;cin>>a>>b;
		add(a,b);
		in[b]++;
		ou[a]++;
	}
	solve();
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值