问题一: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 ;
}
大意:
输入 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 ;
}