【2020牛客NOIP赛前集训营-提高组(第二场)】题解(GCD,包含,前缀,移动)

it2023-11-02  68

文章目录

T1:GCDtitlesolutioncode T2:包含titlesolutioncode(正解code补充在上面了) T3:前缀titlesolutioncode T4:移动titlesolutioncode

T1:GCD

title

solution

非常水,看一眼就知道了 首先我们知道每一个数都有唯一的标准整数分解,即拆成若干个质数的幂的乘积 而我们又知道质数彼此互质, g c d ( ) = 1 gcd()=1 gcd()=1 所以就可以迅速反应到,如果一个数有 ≥ 2 \ge 2 2个质数因子,那么 g c d gcd gcd一定等于 1 1 1 否则 g c d gcd gcd就是唯一的质数因子 这样的话,需要寻找的特殊数一定是幂级递增

欧拉筛出 n n n以内的所有质数,然后进行幂级累乘,时间复杂度就是 O ( n l o g n ) O(nlogn) O(nlogn) 最后加上没有被计算的数的个数即可,因为这些数每个都只会贡献 1 1 1

然后直接干掉这道水题

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

这道题只要了解一点点枚举子集就能 A C AC AC 直接暴力一个数枚举子集 自测大数据跑了1.3s以为会T,但是没想到交上去能跑过诶 好了——数据加强了,终于,我被卡掉了5分 正解就是每次随便丢掉任何一个 1 1 1 O ( n l o g n ) O(nlogn) O(nlogn)

#include <cstdio> #define MAXN 1000005 int n, m; bool vis[MAXN]; int main() { scanf( "%d %d", &n, &m ); for( int i = 1, x;i <= n;i ++ ) { scanf( "%d", &x ); vis[x] = 1; } for( int i = 1e6;i;i -- ) { if( ! vis[i] ) continue; for( int j = 0;j < 20;j ++ ) if( i >> j & 1 ) vis[i ^ ( 1 << j )] = 1; } for( int i = 1, x;i <= m;i ++ ) { scanf( "%d", &x ); if( vis[x] ) printf( "yes\n" ); else printf( "no\n" ); } return 0; }

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,还有暴力过去的 考虑将时间离散化,变成每个门在哪些时间段会打开,用 v e c t o r + p a i r vector+pair vector+pair存储 大概是 n + m n+m n+m个时间段

d p [ i ] dp[i] dp[i]表示最早到达 第 i i i个时间段对应的门 的时间 然后用类似最短路的方法去 d p dp dp转移,每次可以向两边转移(前提是这个门和转移到达的门都打开)

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; }
最新回复(0)