2023.5.24codeforces训练记录

文章介绍了两道编程竞赛题目,第一题涉及计算在给定模数下的特定条件的数的个数,利用循环周期和预处理解决。第二题是基于无向图的有条件最短路问题,采用Dijkstra算法结合图中节点的时间限制找到最早到达目标节点的时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题一:1342C - Yet Another Counting Problem

大意:给定两个模数a b   然后q次询问  每次询问给出一个区间  判断区间内有多少个x满足xmod a modb 不等于 xmod b mod a

思路:由题意得a*b是一个循环周期。且因为a,b<200,循环周期最多为4w。故我们可以先预处理周期内,1~x中满足条件的个数(x<=a*b)。那么对于任意一个x,显然满足条件的个数为x/(a*b)个循环周期的个数以及1~x %(a*b)中满足条件的个数的和。故我们可以先打表,再通过 求出1~r,1~l-1中分别有多少个,然后前者减去后者即可。

代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#define x first
#define y second 

using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N =210;
const LL INF  =  1e10 ;
LL d[N*N] ;
int n ; 


int main()
{

	int T  ;cin >> T;
	while(T--){
		int a,b,q;
		cin >> a >>b >> q;
		memset( d, 0 , sizeof d) ;
		for(int i =1;i <=a*b; ++i){
			d[i] = d[i-1];
			if(  ( i%a)%b != (i%b)%a) d[i]++;
		}
		LL t= a*b ;
		while( q-- ){
			LL l ,r ;cin >>l >> r ;
			//cout<< "l��"<< l/t*d[t]+d[l%t]<<" r:"<< r/t * d[t] + d[r%t]<<endl;
			cout<<  r/t *d[t] + d[r%t] - (l-1)/t *d[t]-d[(l-1)%t] <<endl; 
		}
	}
    return 0 ;
}

问题二:Div. 1 B — Planets

大意:

输入 n(2≤n≤1e5) m(0≤m≤1e5) 表示一个 n 点 m 边的无向图(节点编号从 1 开始)。
然后输入 m 条边,每条边包含 3 个数 a b c(1≤c≤1e4),表示有一条边权为 c 的无向边连接 a 和 b。
保证无自环、无重边。
然后输入 n 行,每行第一个数 k 表示数组 t[i] 的长度,然后输入数组 t[i]。
数组 t[i] 是一个严格递增序列,0≤t[i][j]<1e9。
所有 k 之和 ≤1e5。

初始时间为 0。你从 1 出发,要去 n。
如果你在点 i,但是当前时间在数组 t[i] 中,那么你必须等待 1 秒。如果下一秒仍然在 t[i] 中,那么继续等待 1 秒。依此类推。
输出到达 n 的最早时间。
如果无法到达 n,输出 -1。

思路:显然,这是一个有条件限制的最短路。我们可以使用dijkstra,每当到达一个新点时,需要做的操作是根据该顶点的t[i]数组判断能出发到其他顶点的最早时间,然后再扩展其他新点。并且由dijkstra的正确性可得,每个顶点只会扩展一次,第一次扩展即为最早的到达时间。

代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#define x first
#define y second 

using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<LL , int > PLI;
const int N =1e5 +10 , M = 2e5+10;
const LL INF  =  1e10 ;

int h[N] , e[M] ,ne[M] ,w[M] ,idx;
int  n ; 
vector< vector<LL> >  t;
LL dist[N] ;

void add( int a,int b ,int c ){
	e[idx] = b, ne[idx] =h[a] ,w[idx] =c, h[a] =idx++ ;
}


void dijskra()
{
	for(int i =1;i <=n; ++i) dist[i] = INF  ;
	priority_queue< PLI , vector<PLI> , greater<PLI> > heap;
	heap.push( {0 ,1} ) ;
	while( heap.size()){
		auto val =heap.top(); heap.pop() ;
		int ver =  val.y ; 
		LL distance =  val.x;
		//cout<<ver<<" " <<distance<<endl;
		if( distance >= dist[ver] ) continue;
		dist[ver] =distance;
		if( ver == n) return ;
		
		LL begin = distance ;int  size = t[ver].size();
		int cnt= find( t[ver].begin() ,t[ver].end() , begin)   - t[ver].begin() ;
		if( cnt < size){
			int l = cnt+1 , r= size ;
			while( l < r ){
				int mid = l+r >>1;
				if( t[ver][mid] - t[ver][cnt] == mid-cnt) l = mid+1;
					else r= mid;
			} 
			begin = t[ver][l-1]+1;
		}
		//cout<<"begin time " <<begin<<endl;
		for(int i  = h[ver] ; ~i ; i = ne[i]){
			int j= e[i]  ,size = t[j].size();
			if( dist[j] > begin+ w[i]){
				heap.push( {begin+w[i] , j}) ;
			}
		}
		 
	}
}

int main()
{

	int T  ;T=1;
	while(T--){
		int m ;
		cin >> n >> m ;
		memset( h , -1 ,sizeof h ) ;
		idx =0 ; t.resize( n+1 ) ;
		while( m--){
			int a,b,c;
			cin >>a >>b >> c;
			add( a,b,c) , add( b,a,c) ;
		}
		
		for(int i=1 ; i<=n ; ++i){
			int x; cin >>x;
			while( x--) {
				int v;
				cin >>v ;
				t[i].push_back( v) ;
			}
		}
		dijskra( ) ;
		if( dist[n ]  >= INF/2) cout<<-1<<endl;
			else cout<<dist[n] <<endl;
	}
    return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值