One Bamboo Contest Round #13(Clone from 2019 ICPC Yinchuan)
N. Fibonacci Sequence(补队友题)
print("1 1 2 3 5")
B. So Easy(补队友题)
设\(x_i\)表示第\(i\)行加的值,\(y_i\)表示第\(i\)列加的值。则有\(a_{i,j}=x_i+y_j\)
\(j-1\) | \(j\) | |
---|---|---|
\(i-1\) | \(x_{i-1}+y_{j-1}\) | \(x_{i-1}+y_j\) |
\(i\) | \(x_i+y_{j-1}\) | \(x_i+y_j\) |
所以有\(a_{i,j}=a_{i-1,j}+a_{i,j_1}-a_{i-1,j-1}\)恒成立,当时实际过程种还要再考虑一下边界问题。
#include <bits/stdc++.h>
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
int main(){
int n = read();
auto g = vector( n+1 , vector<int>(n+1) );
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= n ; j ++ )
g[i][j] = read();
int sx = 0 , sy = 0 , tx , ty;
for( int i = 1 ; sx == 0 && sy == 0 && i <= n ; i ++ )
for( int j = 1 ; sx == 0 && sy == 0 && j <= n ; j ++ )
if( g[i][j] == -1 ) sx = i , sy = j;
if( sx-1 >= 1 ) tx = sx-1;
else tx = sx+1;
if( sy-1 >= 1 ) ty = sy-1;
else ty = sy+1;
cout << g[sx][ty] + g[tx][sy] - g[tx][ty];
}
I. Base62(补队友题)
这题其实就是进制转换,但是需要高精度,很麻烦,所以我采用了python,这样一来就变成了进制转换的模板了
cti , itc , num = {} , {} , 0
for i in "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz":
cti[i] = num
itc[num] = i
num += 1
x , y , z = input().split(" ")
x = int(x)
y = int(y)
tmp = 0
for i in z :
tmp = tmp * x + cti[i]
if tmp == 0 :
print("0")
exit(0)
res = []
while tmp > 0 :
t = tmp % y
tmp //= y
res.append( itc[t] )
print( "".join(res[::-1]) )
G. Pot!!(补队友题)
\(p|n\)说明\(p\)是\(n\)的质因子,\(p^m|n,p^{m+1}\nmid n\)说明\(m\)是\(n\)质因数分解后的最高次幂。因为每次乘的数最大是\(10\)所以质因子只有\(2,3,5,7\)
这道题就变成了区间加,区间最值查询。分块写一下就好。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
class Parts{
private:
struct Part{
int l , r , max , tag;
vector<int> val;
Part( int l , int r , int max , int tag , vector<int> val )
: l(l) , r(r) , max(max) , tag(tag) , val(val) {};
};
int n , t;
vector<int> pos;
vector<Part> p;
public:
Parts( int n ) : n(n){
t = sqrt(n);
pos.resize(n+1);
for( int i = 1 ; i <= t ; i ++ )
p.push_back( Part( (i-1)*t+1 , i*t , 0 , 0 , vector<int>() ) );
if( p.back().r < n )
p.push_back( Part(p.back().r+1 , n , 0 , 0 , vector<int>() ) );
for( int i = 1 , j = 0 ; i <= n ; i ++ ){
if( i > p[j].r ) j ++;
p[j].val.push_back(0) , pos[i] = j;
}
}
void update(int l , int r , int d ){
for( int i = pos[l] ; i <= pos[r] ; i ++ ){
if( p[i].l >= l && p[i].r <= r )
p[i].max += d , p[i].tag += d;
else{
for( int j = max( l , p[i].l) - p[i].l ; j <= min( r , p[i].r) - p[i].l ; j ++ )
p[i].val[j] += d;
p[i].max = INT_MIN;
for( auto & j : p[i].val )
j += p[i].tag , p[i].max = max( p[i].max , j );
p[i].tag = 0;
}
}
}
int getMax( int l , int r ){
int res = INT_MIN;
for( int i = pos[l] ; i <= pos[r] ; i ++ ){
if( p[i].l >= l && p[i].r <= r )
res = max( res , p[i].max );
else{
for( int j = max(l,p[i].l)-p[i].l ; j <= min(r,p[i].r)-p[i].l ; j ++ )
res = max( res , p[i].val[j] + p[i].tag );
}
}
return res;
}
};
int32_t main(){
int n = read() , q = read();
Parts p2(n) , p3(n) , p5(n) , p7(n);
for( char s[10] ; q ; q -- ){
scanf("%s" , s );
if( s[1] == 'U' ){
int l = read() , r = read() , d = read() , t = 0;
while( d % 2 == 0 ) d /= 2 , t ++;
if( t > 0 ) p2.update( l , r , t ) , t = 0;
while( d % 3 == 0 ) d /= 3 , t ++;
if( t > 0 ) p3.update( l , r , t ) , t = 0;
while( d % 5 == 0 ) d /= 5 , t ++;
if( t > 0 ) p5.update( l , r , t ) , t = 0;
while( d % 7 == 0 ) d /= 7 , t ++;
if( t > 0 ) p7.update( l , r , t ) , t = 0;
}
else{
int l = read() , r = read();
printf("ANSWER %d\n" , max( { p2.getMax(l,r) , p3.getMax(l,r) , p5.getMax(l,r) , p7.getMax(l,r)} ) );
}
}
}
H. Delivery Route
其实就是单元最短路,但是因为有负权边不能跑Dijkstra,只能跑SPFA。但是,数据被构造过,直接跑SPFA会TLE。所以这里我们要用一个特殊的性质,就是双向边都是正权值,单向边可能是负权值。所以我们可以先在图中只加入双向边,这样图就是若干个连通块,块内跑Dijkstra,把连通块当作一个点,块外跑SPFA即可。
具体的实现步骤
- 首先把双向边都加入,然后跑dfs划分连通块,并且给每个点都标上对应连通块的号
c[i]
,然后对于每个连通块开一个数组part[i]
\(O(n)\)的处理出所以的连通块对应的点。 - 开数组
deg[i]
表示第i
个联通块的入度,把单向边加入到图中,同时deg[c[v]]++
统计所有联通快的入度。 - 开队列
q
,把c[s]
放入进去,在把所有入读为零的块放进去 - 然后取出队头,开始跑Dijkstra
- 把块中所有的点放入的小根堆中
- 取出堆顶
u
,如果被更新过,重复1,否则继续 - 枚举所有的边
(u,v,w)
,更新d[v]
- 如果
c[v]==c[u]
,说明边在块内,v
加入堆中继续做Dijkstra。否则,说明边跨块,deg[c[v]]--
,当deg[c[v]]
为零时,c[v]
加入队列 - 重复2~4,直到堆空结束
- 重复4,直到队空结束
#include <bits/stdc++.h>
#define int long long
using namespace std;
int read(){
int x = 0 , f = 1 , ch = getchar();
while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
if( ch == '-' ) f = -1 , ch = getchar();
while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
return x * f;
}
typedef pair<int,int> PII;
const int N = 50005;
bitset<N>vis;
int n , r , p , s , c[N] , tot = 0;
vector<int> dis, deg;
vector<vector<PII>> e;
vector<vector<int>> part;
void dfs( int x , int id ){
c[x] = id;
for( auto [ v , w ] : e[x] ){
if( c[v] ) continue;
dfs( v , id );
}
return;
}
int32_t main(){
n = read() , r = read() , p = read() , s = read();
e.resize(n+1);
for( int u , v , w ; r ; r -- )
u = read() , v = read() , w = read() , e[u].emplace_back( v , w ) , e[v].emplace_back(u,w);
for( int i = 1 ; i <= n ; i ++ ) if( c[i] == 0 ) dfs( i , ++ tot );
deg.resize( tot+1);
for( int u , v , w ; p ; p -- )
u = read() , v = read() , w = read() , e[u].emplace_back( v , w ) , deg[ c[v] ] ++;
part.resize(tot+1);
for( int i = 1 ; i <= n ; i ++ ) part[ c[i] ].push_back( i );
queue<int> q; q.push( c[s] );
for( int i = 1 ; i <= tot ; i ++ ) if( deg[i] == 0 && i != s ) q.push(i);
dis.resize(n+1) , fill( dis.begin() , dis.end() , INT_MAX ) , dis[s] = 0;
while( q.size() ){
auto it = q.front(); q.pop();
priority_queue< PII , vector<PII> , greater<PII> > heap;
for( auto i : part[it] ) heap.emplace( dis[i] , i );
while( heap.size() ){
auto [ d , u ] = heap.top(); heap.pop();
if( vis[u] ) continue; vis[u] = 1;
for( auto [ v , w ] : e[u] ){
if( d != INT_MAX && dis[v] > d + w ){
dis[v] = d + w;
if( c[u] == c[v] ) heap.emplace( dis[v] , v );
}
if( c[u] != c[v] ){
deg[ c[v] ] --;
if( deg[ c[v] ] == 0 ) q.push( c[v] );
}
}
}
}
for( int i = 1 ; i <= n ; i ++ ) ( dis[i] >= INT_MAX ? printf("NO PATH\n") : printf( "%d\n" , dis[i] ) );
return 0;
}