【2020牛客NOIP赛前集训营-提高组(第二场)】题解(GCD,包含,前缀,移动)
文章目錄
- T1:GCD
- title
- solution
- code
- T2:包含
- title
- solution
- code(正解code補充在上面了)
- T3:前綴
- title
- solution
- code
- T4:移動
- title
- solution
- code
T1:GCD
title
solution
非常水,看一眼就知道了
首先我們知道每一個數都有唯一的標準整數分解,即拆成若干個質數的冪的乘積
而我們又知道質數彼此互質,gcd()=1gcd()=1gcd()=1
所以就可以迅速反應到,如果一個數有≥2\ge 2≥2個質數因子,那么gcdgcdgcd一定等于111
否則gcdgcdgcd就是唯一的質數因子
這樣的話,需要尋找的特殊數一定是冪級遞增
歐拉篩出nnn以內的所有質數,然后進行冪級累乘,時間復雜度就是O(nlogn)O(nlogn)O(nlogn)
最后加上沒有被計算的數的個數即可,因為這些數每個都只會貢獻111
然后直接干掉這道水題
code
#include <cstdio> #define ll long long #define MAXN 10000000 int a, b, cnt; int prime[MAXN + 5]; bool vis[MAXN + 5]; ll ans[MAXN + 5];void sieve() {for( int i = 2;i <= MAXN;i ++ ) {if( ! vis[i] )vis[i] = 1, prime[++ cnt] = i;for( int j = 1;i * prime[j] <= MAXN && j <= cnt;j ++ ) {vis[i * prime[j]] = 1;if( i % prime[j] == 0 ) break;}} }int main() {sieve();for( int i = 1;i <= MAXN;i ++ )ans[i] = 1;for( int i = 1;i <= cnt;i ++ ) {int j = 1;while( 1ll * j * prime[i] <= MAXN ) {j *= prime[i];ans[j] = prime[i];}}for( int i = 1;i <= MAXN;i ++ )ans[i] += ans[i - 1];scanf( "%d %d", &a, &b );printf( "%lld\n", ans[b] - ans[a - 1] );return 0; }T2:包含
title
solution
這道題只要了解一點點枚舉子集就能ACACAC
直接暴力一個數枚舉子集
自測大數據跑了1.3s以為會T,但是沒想到交上去能跑過誒
好了——數據加強了,終于,我被卡掉了5分
正解就是每次隨便丟掉任何一個111,O(nlogn)O(nlogn)O(nlogn)
code(正解code補充在上面了)
#include <cstdio> #include <iostream> using namespace std; #define MAXN 100005 #define MAXM 1000000 int n, m, cnt, maxx; int a[MAXN]; bool vis[MAXM + 5];int main() {scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &a[i] );maxx = max( maxx, a[i] );}for( int i = 1;i <= n;i ++ ) {int x = a[i];if( vis[x] ) continue;vis[x] = 1, cnt ++;if( cnt == maxx ) continue;for( int j = x;j;j = ( ( j - 1 ) & x ) )if( ! vis[j] ) {vis[j] = 1;cnt ++;if( cnt == maxx ) break;}}for( int i = 1, x;i <= m;i ++ ) {scanf( "%d", &x );if( vis[x] ) printf( "yes\n" );else printf( "no\n" );}return 0; }T3:前綴
title
solution
大模擬!!無需多說慢慢敲,高精直接上
code
#include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define int long long #define mod 998244353 #define MAXN 100005 vector < int > pos[30]; char s[MAXN], t[MAXN]; int pi[MAXN][2], num[MAXN]; int n, ans;int calc( int l, int r, int siz, int len ) {int cnt = 0, ip;for( int i = l;i <= r;i ++ )num[i - l + 1] = t[i] ^ 48;for( ip = r - l + 1;! num[ip];ip -- );num[ip] --;for( int i = ip + 1;i <= r - l + 1;i ++ )num[i] = 9;int g = 0, R = 0;for( int i = 1;i <= r - l + 1;i ++ )g = R * 10 + num[i], num[++ cnt] = g / siz, R = g % siz;g = 0;for( int i = cnt;i;i -- )g += len * num[i], num[i] = g % 10, g /= 10;for( int i = 1;i <= cnt;i ++ )g = ( g * 10 + num[i] ) % mod;ans = ( ans + g ) % mod;return R; }signed main() {scanf( "%s", s );int lens = strlen( s );for( int i = 0;i < lens;i ++ )pos[s[i] ^ 96].push_back( i ), pi[i][0] = pos[s[i] ^ 96].size() - 1;for( int i = 0;i < lens;i ++ )pos[0].push_back( i ), pi[i][1] = i;scanf( "%lld", &n );while( n -- ) {ans = 0;scanf( "%s", t );int lent = strlen( t );int l = 0, r = 0, now = lens - 1, nxt, flag = 1, f;for( ;l < lent;l = ++ r ) {if( t[l] == '*' ) t[l] = 96, f = 1;else f = 0;int id = t[l] ^ 96, siz = pos[id].size();if( ! siz ) { flag = 0; break; }if( pos[id][siz - 1] <= now ) nxt = pos[id][0];else nxt = *upper_bound( pos[id].begin(), pos[id].end(), now );if( now < nxt ) ans = ( ans + nxt - now ) % mod, now = nxt;else ans = ( ans + lens + nxt - now ) % mod, now = nxt;if( l + 1 < lent && isdigit( t[l + 1] ) )for( ;r + 1 < lent && isdigit( t[r + 1] );r ++ );if( l < r ) {int R = calc( l + 1, r, siz, lens );if( R ) {nxt = pos[id][( pi[now][f] + R ) % siz];if( now < nxt ) ans = ( ans + nxt - now ) % mod, now = nxt;else ans = ( ans + lens + nxt - now ) % mod, now = nxt;}}}if( ! flag ) printf( "-1\n" );else printf( "%lld\n", ans );}return 0; }T4:移動
title
solution
用心出題,用腳造數據
有的代碼不考慮后退錯誤貪心都能AC,還有暴力過去的
考慮將時間離散化,變成每個門在哪些時間段會打開,用vector+pairvector+pairvector+pair存儲
大概是n+mn+mn+m個時間段
設dp[i]dp[i]dp[i]表示最早到達 第iii個時間段對應的門 的時間
然后用類似最短路的方法去dpdpdp轉移,每次可以向兩邊轉移(前提是這個門和轉移到達的門都打開)
code
#include <queue> #include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std; #define Pair pair < int, int > #define inf 0x3f3f3f3f #define MAXN 100005 struct node {int id, x, t;node() {}node( int Id, int X, int T ) {id = Id, x = X, t = T;} }; priority_queue < node, vector < node >, greater < node > > q; vector < Pair > G[MAXN], tmp; int n, m; int id[MAXN << 1], dp[MAXN << 1];bool cmp( Pair x, Pair y ) {return x.first < y.first; }bool operator > ( node x, node y ) {return x.t > y.t; }void calc( node p, int x ) {int r = G[p.x][p.id - id[p.x]].second;int i = lower_bound( G[x].begin(), G[x].end(), make_pair( p.t + 1, 0 ) ) - G[x].begin() - 1;if( G[x][i].second >= p.t + 1 ) {if( dp[id[x] + i] > p.t + 1 ) {dp[id[x] + i] = p.t + 1;q.push( node( id[x] + i, x, p.t + 1 ) );}}i ++;while( i < G[x].size() && G[x][i].first <= r + 1 ) {if( dp[id[x] + i] > G[x][i].first ) {dp[id[x] + i] = G[x][i].first;q.push( node( id[x] + i, x, G[x][i].first ) );}i ++;} }void solve() {memset( dp, 0x3f, sizeof( dp ) );q.push( node( 0, 0, 0 ) );dp[0] = 0;while( ! q.empty() ) {node now = q.top(); q.pop();if( now.t > dp[now.id] ) continue;if( now.x > 0 ) calc( now, now.x - 1 );if( now.x <= n ) calc( now, now.x + 1 );} }int main() {scanf( "%d %d", &n, &m );for( int i = 1, a, b, c;i <= m;i ++ ) {scanf( "%d %d %d", &a, &b, &c );G[a].push_back( make_pair( b, c ) );}G[0].push_back( make_pair( 0, inf ) );G[n + 1].push_back( make_pair( 0, inf ) );id[1] = 1;for( int i = 1;i <= n;i ++ ) {tmp.clear();sort( G[i].begin(), G[i].end(), cmp );int r = -1;for( int j = 0;j < G[i].size();j ++ ) {if( G[i][j].first > r + 1 ) tmp.push_back( make_pair( r + 1, G[i][j].first - 1 ) );r = max( r, G[i][j].second );}tmp.push_back( make_pair( r + 1, inf ) );G[i] = tmp;id[i + 1] = id[i] + G[i].size();}solve();printf( "%d\n", dp[id[n + 1]] );return 0; }總結
以上是生活随笔為你收集整理的【2020牛客NOIP赛前集训营-提高组(第二场)】题解(GCD,包含,前缀,移动)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mac怎么同时开启多个微信?苹果电脑微信
- 下一篇: [2020-11-23 contest]