l比賽題目鏈接
A.Orac and Factors
題意:給你一個數每次遞歸地加上它自己的最小非1因數,問k k k 次之後這個數是多少?
思路:偶數一直加2,奇數先找到最小因數,加上後一定是個偶數,然後一直加2。
#include <bits/stdc++.h>
const int MAXN = 1e5 + 10 ;
typedef long long ll;
using namespace std;
int main ( ) {
int T;
cin >> T;
while ( T-- ) {
ll n, k;
cin >> n >> k;
if ( n & 1 ) {
for ( int i = 3 ; ; i++ ) {
if ( n % i == 0 ) {
n + = i;
break ;
}
}
n = n + ( k - 1 ) * 2ll ;
}
else {
n = n + k * 2ll ;
}
cout << n << endl;
}
}
B.Orac and Models
題意:給你一個數列,讓你從中選取一個嚴格上升的子序列,且對於子序列中的任意兩個下標i , j ( i < j ) i,j(i<j) i , j ( i < j ) ,在原序列中的下標p i , p j ( p i < p j ) p_i,p_j(p_i<p_j) p i , p j ( p i < p j ) ,都有p j p_j p j 整除p i p_i p i ,問這樣的子序列長度最長是多少?。
思路:定義d p [ i ] dp[i] d p [ i ] 爲原序列前i i i 個數的最長答案,有轉移:d p [ j ] = m a x { d p [ i ] + 1 } i f ( i ∣ j & a [ j ] > a [ i ] ) dp[j] = max\{dp[i] + 1\} \ if(i|j \ \&\ a[j]>a[i] ) d p [ j ] = m a x { d p [ i ] + 1 } i f ( i ∣ j & a [ j ] > a [ i ] ) ,複雜度O ( n l o g ( n ) ) O(nlog(n)) O ( n l o g ( n ) ) 。ps:比賽的時候我dfs寫的,又醜又長還會wa。。。。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 1e5 + 10 ;
const int INF = 0x3f3f3f3f ;
int a[ MAXN] ;
int dp[ MAXN] ;
int main ( ) {
int T;
cin >> T;
while ( T-- ) {
int n;
cin >> n;
for ( int i = 1 ; i <= n; i++ ) {
cin >> a[ i] ;
dp[ i] = 1 ;
}
int ret = 1 ;
for ( int i = 1 ; i <= n; i++ ) {
for ( int j = 2 * i; j <= n; j + = i) {
if ( a[ j] > a[ i] ) {
dp[ j] = max ( dp[ j] , dp[ i] + 1 ) ;
ret = max ( ret, dp[ j] ) ;
}
}
}
cout << ret << endl;
}
}
C.Orac and LCM
題意:求任兩個數的lcm的gcd
思路:設素數p p p ,假設最後的答案有p k p^k p k 這樣一個因子,那麼p k p^k p k 至少是原來的n − 1 n-1 n − 1 個數的因子。反證法可以證明。那麼之後只要將所有的數進行因式分解,之後記錄並統計一下各個素數出現的次數即可。
另一種做法(題解):每次求出除了當前數外其他數的gcd(用前後綴)。最後再求這些gcd的lcm即爲答案,這種做法可以使得數的範圍更大~1e9,上個做法應該只能1e6左右。
#include <bits/stdc++.h>
const int MAXN = 1e5 + 10 ;
typedef long long ll;
using namespace std;
const int N = 1e5 + 10 ;
int dp[ N] ;
const int INF = 0x3f3f3f3f ;
#define pa pair<int, int>
const int maxn = 1e6 + 1000 ;
int prime[ maxn] = { 0 } , phi[ maxn] = { 0 } , tot = 0 ;
void euler ( ) {
phi[ 1 ] = 1 ;
for ( int i = 2 ; i < maxn; i++ ) {
if ( ! phi[ i] ) {
prime[ tot++ ] = i;
phi[ i] = i - 1 ;
}
for ( int j = 0 ; j < tot && i * prime[ j] < maxn; j++ ) {
if ( i % prime[ j] == 0 ) {
phi[ i * prime[ j] ] = phi[ i] * prime[ j] ;
break ;
}
phi[ i * prime[ j] ] = phi[ i] * phi[ prime[ j] ] ;
}
}
}
map< int , vector< int >> ma;
#define pa pair<int, int>
vector< pa> factor;
void init ( int n) {
factor. clear ( ) ;
for ( int i = 0 ; prime[ i] * prime[ i] <= n && i < tot; i++ ) {
if ( n % prime[ i] == 0 ) {
factor. emplace_back ( prime[ i] , 0 ) ;
for ( ; n % prime[ i] == 0 ; n / = prime[ i] ) factor. back ( ) . second++ ;
}
}
if ( n > 1 ) factor. emplace_back ( n, 1 ) ;
for ( auto it : factor) {
ma[ it. first] . push_back ( it. second) ;
}
}
int arr[ MAXN] ;
int main ( ) {
euler ( ) ;
cin. tie ( 0 ) ;
ios: : sync_with_stdio ( 0 ) ;
int n;
while ( cin >> n) {
ma. clear ( ) ;
for ( int i = 1 ; i <= n; i++ ) {
cin >> arr[ i] ;
init ( arr[ i] ) ;
}
ll ret = 1 ;
for ( auto & it : ma) {
int tt = 0 ;
if ( it. second. size ( ) == n) {
sort ( it. second. begin ( ) , it. second. end ( ) ) ;
tt = it. second[ 1 ] ;
}
else if ( int ( it. second. size ( ) ) == n - 1 ) {
sort ( it. second. begin ( ) , it. second. end ( ) ) ;
tt = it. second[ 0 ] ;
}
for ( int i = 0 ; i < tt; i++ ) ret * = ll ( it. first) ;
}
cout << ret << endl;
}
}
D.Orac and Medians
題意:一個數組,每次選擇一個區間,將他們都變爲這個區間的中位數(偶數個的時候中位數取較小的那個),問最後能否把整個數組都變成k k k 。
思路:首先判斷有沒有k k k ,沒k k k 那是肯定不行的,接着看下每連着的三個數是不是有兩個都大於等於k就行了。因爲一個小數可以直接把它隔壁的大數拖下水,而大數要兩個以上才能不斷把小數變大。比賽時候看錯題了,一下子沒思路,而且朋友叫我去打lol去了草。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 1e5 + 10 ;
const int INF = 0x3f3f3f3f ;
int a[ MAXN] ;
int main ( ) {
int T;
cin >> T;
while ( T-- ) {
int n, k;
cin >> n >> k;
int kf = 0 ;
for ( int i = 0 ; i < n; i++ ) {
cin >> a[ i] ;
if ( a[ i] == k) kf = 1 ;
}
if ( n == 1 || n == 2 ) {
if ( n == 2 ) sort ( a, a + 2 ) ;
if ( a[ 0 ] == k) cout << "yes\n" ;
else cout << "no\n" ;
}
else {
int f = 0 ;
for ( int i = 2 ; i < n; i++ ) {
vector< int > t = { a[ i] , a[ i - 1 ] , a[ i - 2 ] } ;
sort ( t. begin ( ) , t. end ( ) ) ;
if ( t[ 1 ] >= k && t[ 2 ] >= k) {
f = 1 ;
break ;
}
}
if ( f && kf) cout << "yes\n" ;
else cout << "no\n" ;
}
}
}
E.Orac and Game of Life
題意:給你方格的初始細胞狀態(0或1),當週圍細胞有和自己狀態一樣時,會改變狀態(1->0&0->1),否則維持當前狀態不變,然後每次問題在t t t 時刻( x , y ) (x,y) ( x , y ) 細胞是0還是1。
思路:一個細胞開始變改變狀態後,就停不下來了(因爲周圍和它一起變),所以只要bfs統計一下每個細胞是從什麼時候開始變色的就行了。ps:我覺得這比D簡單多了。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 1e3 + 10 ;
const ll INF = 2e18 ;
char ma[ MAXN] [ MAXN] ;
ll step[ MAXN] [ MAXN] ;
struct nod{ int x, y; } ;
int dx[ ] = { 0 , 0 , - 1 , 1 } ;
int dy[ ] = { - 1 , 1 , 0 , 0 } ;
int n, m, q;
void bfs ( ) {
queue< nod> Q;
for ( int i = 0 ; i < n; i++ ) {
for ( int j = 0 ; j < m; j++ ) {
step[ i] [ j] = INF;
for ( int t = 0 ; t < 4 ; t++ ) {
int ni = i + dx[ t] ;
int nj = j + dy[ t] ;
if ( ni >= 0 && ni < n && nj >= 0 && nj < m
&& ma[ ni] [ nj] == ma[ i] [ j] ) {
Q. push ( { i, j } ) ;
step[ i] [ j] = 0 ;
break ;
}
}
}
}
while ( ! Q. empty ( ) ) {
nod cur = Q. front ( ) ;
Q. pop ( ) ;
for ( int i = 0 ; i < 4 ; i++ ) {
int nx = cur. x + dx[ i] ;
int ny = cur. y + dy[ i] ;
if ( nx >= 0 && nx < n && ny >= 0 && ny < m && step[ nx] [ ny] == INF) {
step[ nx] [ ny] = step[ cur. x] [ cur. y] + 1 ;
Q. push ( { nx, ny } ) ;
}
}
}
}
int main ( ) {
cin >> n >> m >> q;
for ( int i = 0 ; i < n; i++ ) cin >> ma[ i] ;
bfs ( ) ;
while ( q-- ) {
int x, y;
ll t;
cin >> x >> y >> t;
x-- , y-- ;
if ( step[ x] [ y] == INF || step[ x] [ y] > t) cout << ma[ x] [ y] << endl;
else {
t - = step[ x] [ y] ;
if ( t & 1ll ) cout << 1 - int ( ma[ x] [ y] - '0' ) << endl;
else cout << ma[ x] [ y] << endl;
}
}
}