LibreOJ NOIP Round #1 —— 蒟蒻总结&部分题解

来源:互联网 发布:人工智能经济学 编辑:程序博客网 时间:2024/05/17 21:51

LibreOJ NOIP Round #1 Day 1

Day 1

T1. DNA 序列

水题,最直观的解法是hash,发现k<=10后发现转化为二进制压位也行
定位:noip d1t1,送分题
#include <bits/stdc++.h>using namespace std;const int N = 5000000 + 5;char s[N];int a[N<<1], b[1<<20], K, n, now, ans;int main(){scanf( "%s", s + 1 ); n = strlen(s + 1);scanf( "%d", &K );for( int i = 1; i <= n; i++ ){if( s[i] == 'A' ) a[i*2-1] = 0, a[i*2] = 0;if( s[i] == 'G' ) a[i*2-1] = 0, a[i*2] = 1;if( s[i] == 'C' ) a[i*2-1] = 1, a[i*2] = 0;if( s[i] == 'T' ) a[i*2-1] = 1, a[i*2] = 1;}for( int i = 1; i <= K*2; i++ ) now <<= 1, now += a[i];for( int i = K * 2; i <= n * 2; i += 2 ){b[now]++;if( b[now] > ans ) ans = b[now];if( i == n * 2 ) break;now <<= 1; now += a[i + 1];now %= (1<<(K*2));now <<= 1; now += a[i + 2];now %= (1<<(K*2));}printf( "%d\n", ans );return 0;}

T2. 递推数列

这道题具有一些迷惑性,我们看到k>0
首先考虑ai,ai-1同号,可以推出ai+1也同号并且绝对值更大
也就是在这之后ai具有单调性
那我们只需要求出没有单调性之前的所有数就行了(有单调性之后还是要算出更大的)
定义:不按常理的题
题解中的证明:

设 bi=∣ai∣b_i=|a_i|bi=ai,由正负交错有 ∀i∈[2,M),bi=−kbi−1+bi−2\forall i\in[2,M), b_i=-k b_{i-1}+b_{i-2}i[2,M),bi=kbi1+bi2,移项得 bi−2=kbi−1+bib_{i-2}=k b_{i-1}+b_ibi2=kbi1+bi

那么 bi−2=kbi−1+bi≥(k+1)bib_{i-2}=k b_{i-1}+b_i\ge (k+1)b_ibi2=kbi1+bi(k+1)bi,可得 M≤2logk+1a0M\le 2\log_{k+1} a_0M2logk+1a0

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N = 300000 + 5;ll a[105]; int m, n, s[N], K, minsi, maxsi, t;int main(){scanf( "%d", &m ); for( int i = 1; i <= m; i++ ) scanf( "%d", &s[i] );scanf( "%d", &n );while( n-- ){scanf( "%lld%lld%d", &a[0], &a[1], &K ); minsi = maxsi = s[1];if( !a[0] && !a[1] ){ printf( "%d %d\n", s[1], s[1] ); continue; }for( t = 2; t <= 100 && abs( a[t] = a[t - 1] * K + a[t - 2] ) <= 1e14; t++ ); t--;for( int i = 1; i <= m && s[i] <= t; i++ ){minsi = ( a[s[i]] < a[minsi] ) ? s[i] : minsi;maxsi = ( a[s[i]] > a[maxsi] ) ? s[i] : maxsi;}if( s[m] > 100 ) a[t] < 0 ? minsi = s[m] : maxsi = s[m];printf( "%d %d\n", maxsi, minsi );}return 0;}

T3. 旅游路线

这道题看了题解(chao了代码)后觉得挺简单的,但是考试时做得出来?
这可能就相当于我对去年noip t3 t6的定义吧(虽然那两道确实简单啊)

w[i][j][k]:从i到j经过不超过2^k长度的最长距离

dis[i][j]:从i出发(先在i加油到j的最大路程(可能到j加油也可能不走))

dp[i][j]:从i出发带j元钱的最大路程

从w数组转移到dis数组的时候要注意要用一个f数组存中间点

转移方程:

w[i][j][k] = w[i][l][k - 1] + w[l][j][k - 1]

f[j] = g[l] + w[l][j][k]

dp[i][k] = max{ dp[j][k - p[i]] + dis[i][j] }

#include <bits/stdc++.h>using namespace std;typedef long long ll;const ll inf = 2e15;int n, m, C, T, last[105], cnt, p[105], c[105]; ll w[105][105][20], g[105], f[105], dis[105][105], dp[105][10005];/*price youliang*//*ÿÐаüº¬Èý¸öÕýÕûÊý si,qi,di,ÃèÊöÒ»´ÎÂÃÓμƻ®£¬ÂÃÓεÄÆðµãΪ±àºÅΪ siµÄ¾°µã£¬³ö·¢Ê±´øÁË qiԪǮ£¬Ä¿±ê·³ÌΪ di.*/int main(){scanf( "%d%d%d%d", &n, &m, &C, &T );for( int i = 1; i <= n; i++ ) scanf( "%d%d", &p[i], &c[i] ), c[i] = min( c[i], C );memset( w, 0xc2, sizeof(w) ); for( int i = 1; i <= n; i++ ) w[i][i][0] = 0;for( int i = 1, u, v, ww; i <= m; i++ ) scanf( "%d%d%d", &u, &v, &ww ), w[u][v][0] = max( w[u][v][0], (ll)ww );for( int k = 1; k <= 18; k++ )for( int l = 1; l <= n; l++ )for( int i = 1; i <= n; i++ )for( int j = 1; j <= n; j++ )w[i][j][k] = max( w[i][j][k], w[i][l][k - 1] + w[l][j][k - 1] );for( int i = 1; i <= n; i++ ){for( int j = 1; j <= n; j++ ) g[j] = ( i == j ? 0 : -inf ), f[j] = -inf;for( int k = 18; k >= 0; k-- )if( c[i] & (1<<k) ){for( int j = 1; j <= n; j++ )for( int l = 1; l <= n; l++ )f[j] = max( f[j], g[l] + w[l][j][k] );for( int j = 1; j <= n; j++ ) g[j] = f[j];}for( int j = 1; j <= n; j++ ) dis[i][j] = g[j];}int lim = n * n;for( int k = 0; k <= lim; k++ )for( int i = 1; i <= n; i++ )if( k >= p[i] )for( int j = 1; j <= n; j++ )dp[i][k] = max( dp[i][k], dp[j][k - p[i]] + dis[i][j] );while( T-- ){int S, Q, D;scanf( "%d%d%d", &S, &Q, &D );int ans = Q + 1;for( int i = 0; i <= Q; i++ )if( dp[S][i] >= D ){ ans = i; break; }printf( "%d\n", Q - ans );}return 0;}

Day 2

T1. 游戏

我是不是太弱了,t1想了那么久都没有想出来。

完全图重有一个1个环的 Example:1-2-3-1

我们猜测一定可以贪心地拆成完全图

试了所有数据后发现有解,所以贪心(逗逼解法)

定义:noip d2t1 但是感觉太坑了,与数列递推一样坑

#include <bits/stdc++.h>using namespace std;int f( int xx ){ return xx * (xx - 1) * (xx - 2) / 6; }int x, n, mp[505][505];int main(){scanf( "%d", &x );for( int i = 500; i >= 3; i-- ){if( x >= f(i) ){x -= f(i);for( int j = n + 1; j <= n + i; j++ )for( int k = j + 1; k <= n + i; k++ )mp[j][k] = 1;n += i;i++;}}printf( "%d\n", n );for( int i = 1; i <= n; i++ ){for( int j = i + 1; j <= n; j++ )printf( "%d ", mp[i][j] );puts("");}return 0;}

T2. 七曜圣贤

我觉得这道题比上一道题好想的多好吗

首先用一个队列q维护飞出去的红茶是个人都想得到,维护一个数据结构,存到是这个队列里面的元素

用一个bool数组存一样红茶买没有买过, 用一个变量now表示1到now都被买过了(只会增长)

购买操作:改一个bool,跳now

飞出去操作:入队尾,入这个数据结构

捡回来操作:队首出

显然这时答案就是min( now, 队列里面所有点编号的最小值 )

没错,这个数据结构就是单调队列

定义:类似去年蚯蚓,但是更简单

#include <bits/stdc++.h>using namespace std;namespace IO{int c;unsigned int seed;unsigned int randnum(){seed ^= seed<<13;seed ^= seed>>17;seed ^= seed<<5;return seed;}inline int read( int &x ){ scanf( "%d", &x ); return x; }inline void init_case( int &m, int &a, int &b, int &d, int p[] ){scanf( "%d%u%d%d%d%d", &m, &seed, &a, &b, &c, &d );for( int i = 1; i <= m; i++ ){if( randnum() % c == 0 ) p[i] = -1;else p[i] = randnum() % b;}}inline void update_ans( unsigned int &ans_sum, unsigned int cur_ans, int no ){const static unsigned int mod = 998244353;ans_sum ^= ( 1LL * no * (no + 7) % mod * cur_ans % mod );}}using IO::read;using IO::init_case;using IO::update_ans;bool incar[2000005], fly[2000005];unsigned int q1[2000005], t1, h1, q2[2000005], t2, h2;/*now:当前最大且已经被买过q1:按扔出时间递增 q2:扔出时间递增,编号递增( 1 3 5 2 8 4 -> 1 2 4 ) *//*pi==-1 最早飞出的回收否则,如果没有买过就买一个否则,如果在车上,则飞出否则,最早飞出的回收,不存在则忽略 */int main(){static int p[2000005];int T; read( T );int m, a, b, d;while( T-- ){unsigned int ans_sum = 0, cur_ans = 0, now = 0;t1 = t2 = 0; h1 = h2 = 1;init_case( m, a, b, d, p );memset( q1, 0, sizeof(q1) );memset( q2, 0, sizeof(q2) );memset( fly, 0, sizeof(fly) );memset( incar, 0, sizeof(incar) );for( int i = 1; i <= a + 1; i++ ) incar[i] = 1;while( incar[now + 1] ) now++;for( int i = 1; i <= m; i++ ){p[i]++;if( p[i] == 0 ){if( d ) continue;if( h1 > t1 ) continue;fly[q1[h1]] = 0;if( q1[h1] == q2[h2] ) h1++, h2++;else h1++;}else if( !incar[p[i]] ){incar[p[i]] = 1;while( incar[now + 1] ) now++;}else if( incar[p[i]] && !fly[p[i]] ){if( d ) continue;fly[p[i]] = 1;q1[++t1] = p[i];while( t2 >= h2 && p[i] < q2[t2] ) t2--;q2[++t2] = p[i];}else {if( d ) continue;if( h1 > t1 ) continue;fly[q1[h1]] = 0;if( q1[h1] == q2[h2] ) h1++, h2++;else h1++;}cur_ans = now;if( h2 <= t2 ) cur_ans = min( cur_ans, q2[h2] - 1 );update_ans( ans_sum, cur_ans, i );        }printf( "%u\n", ans_sum );}return 0;}/*103000 951860881 2869 3500 5 02000 220202994 1745 3400 15 13000 930087169 1624 3500 50 03000 881772733 2368 3500 15 03000 466277267 1122 3500 54 02900 742047150 1965 2500 25 03000 531934116 783 2500 10000000 13000 175160586 2783 2500 5 02333 229062998 2594 3500 55 03000 555447828 2489 3500 555 0*/ 子任务 #1

T3. 序列划分

定义:NOI d1t2

做不来

原创粉丝点击