一道贪心,喵?c++
好吧其实就是个贪心,最大值比较简单,最小值不太好搞看看代码本身理解git
#include <bits/stdc++.h> #define LL long long using namespace std; inline int read() { register int x = 0; register char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ch - '0'; ch = getchar(); } return x; } int main() { LL n , x , y , k , xx , yy , w; LL ans ; while( scanf( "%lld" , & x ) == 1 ) { xx = x , y = yy = read() , n = read(); //特判 if( n == 1 ) { if( x > y ) puts("3 3"); else if( x == y ) puts("1 1"); else puts("0 0"); continue; } //max w = n - 1; k = min( n - 1 , x ) , x -= k , w -= k , ans = k * 3 ; if( x > y ) ans += 3; else if( x == y ) ans += 1; ans += w; printf("%lld " , ans ); //min if( xx > yy ) { n -- , ans = 3 ; //把全部的 x 都放到一个格子里,保证只赢一次 k = min( yy , n ) , ans += n - k; //再给剩下的格子尽量的放 y printf( "%lld\n" , ans ); continue; } if( xx == yy ) { if( n >= 3 && yy >= 3 ) { // 同 xx > yy n -- , ans = 3 ; k = min( yy , n ) , ans += n - k; printf( "%lld\n" , ans ); } else printf( "%lld\n" , n ); //直接所有平局 continue; } // 对于xx<yy的状况 n -- ; ans = 3 + n - ( min( n , yy ) ); // 把全部的 x 放在一个格子里,剩下的格子每一个放一个 y yy -= xx; ans = min( ans , 1 + n - min( n , yy ) ); // 在一个格子里抵消掉全部的 x 后面的所有放 y yy --; ans = min( ans , n - min( n , yy ) ); // 在保证不会赢的状况下,尽量的放 y printf( "%lld\n" , ans ); } return 0; }
这就是道数据结构模板题,方法不少我用是分块算法
#include<bits/stdc++.h> #define L( x ) ( ( x - 1 ) * len + 1 ) #define R( x ) ( x * len ) #define pos( x ) ( ( x - 1 ) / len + 1 ) using namespace std; const int N = 100000 , M = 1000; int n , m , len , pos[N] , last , gp[M]; int tag[M] , v[N]; inline int read() { register int x = 0; register char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ch - '0'; ch = getchar(); } return x; } int main() { n = read() , last = m = read() , len = sqrt( 1.0 * m ); for( register int i = 1 ; i <= m ; gp[ pos(i) ] ++ , v[i] = 1 , i ++ ); for( register int l , r , p , q , sum ; n >= 1 ; n -- ) { l = read() , r = read() , p = pos( l ) , q = pos( r ) , sum = 0; if( last == 0 ) { puts("0"); continue; } if( p == q ) { for( register int i = l ; i <= r ; i ++ ) { if( tag[p] ) break; sum += v[i] , gp[q] -= v[i] , v[i] = 0; } printf( "%d\n" , last - sum ); last -= sum ; continue; } for( register int i = l ; i <= R( p ) && !tag[p] ; sum += v[i] , gp[p] -= v[i] , v[i] = 0 , i ++ ); for( register int i = r ; i >= L( q ) ; i -- ) { if( tag[q] ) break; sum += v[i] , gp[q] -= v[i] , v[i] = 0; } for( register int i = p + 1 ; i <= q - 1 ; i ++ ) { if( tag[i] ) continue; sum += gp[i] , tag[i] = 1; } printf( "%d\n" , last - sum ); last -= sum; } }
显然是道树状数组的题目,区间修改,单点查询,维护一个差分序列数组
本题主要有两个坑点数据结构
#include <bits/stdc++.h> #define lowbit( x ) ( x & -x ) using namespace std; const int N = 1000005; int n , m , bit[N]; char buf[ 1 << 15 ] , * fs , * ft ; inline char getc(){ return ( fs == ft && ( ft = ( fs = buf ) + fread( buf , 1 , 1 << 15 , stdin ) , fs == ft ) ) ? 0 : * fs ++ ; } inline int read() { register int x = 0 , f = 1 ; register char ch = getc() ; while( !isdigit( ch ) ) { if( ch == '-' ) f = -1 ; ch = getc(); } while( isdigit( ch )) { x = ( x << 3 ) + ( x << 1 ) + ch - '0' ; ch = getc(); } return x * f; } inline void put( int x ) { if( x == 0 ) { putchar( '0' ); putchar( '\n' ); return; } if( x < 0 ) { putchar( '-' ); x =- x; } register int num = 0; register char ch[16]; while( x ) ch[ ++ num ] = x % 10 + '0' , x /= 10 ; while( num ) putchar(ch[num--]) ; putchar('\n'); } inline int query( int x ) { register int sum = 0; for( register int i = x ; i >= 1 ; i -= lowbit( i ) ) sum += bit[i]; return sum; } inline void add( int x , int w ) { for( register int i = x ; i <= n ; i += lowbit( i ) ) bit[i] += w; return ; } int main() { n = read() + 1, m = read(); for( register int op , l , r ; m >= 1 ; m -- ) { op = read() , l = read() + 1 ; if( op == 1 ) r = read() + 1 , add( l , 1 ) , add( r + 1 , -1 ); else put( query(l) ); } return 0; }
用线段树统计一下个数,最后作个除法,没啥难的,主要是要知道怎么用线段树维护一个桶吧优化
#include <bits/stdc++.h> #define LL long long #define lowbit( x ) ( x & - x ) using namespace std; const int N = 1000010; int n , m , a[N] , bit[N] , tp; LL sum; inline int read() { register int x = 0; register char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ch - '0'; ch = getchar(); } return x; } inline void add( int x ) { for( register int i = x ; i <= tp ; bit[i] ++ , i += lowbit( i ) ); } inline LL query( int x ) { register LL res = 0; for( register int i = x ; i >= 1 ; res += bit[i] , i -= lowbit( i ) ); return res; } int main() { n = read() , m = read(); for( register int i = 1 ; i <= n ; a[i] = read() , tp = max( tp , a[i] ) , i ++ ); for( register int i = 1 ; i <= n ; add( a[i] ) , i ++ ); for( register int i = 1 ; i <= n ; i ++ ) { sum += query( m - a[i] ); if( a[i] <= m - a[i] ) sum --; } register double ans = (double)sum / (double)( n * n - n ); printf( "%.2lf\n" , ans ); return 0; }
都说这是到动态规划,当我不想用动态规划,因而就有了搜索的作法ui
其实找一份背包的代码,你会发现原理都差很少spa
y > m
时,ans = max( ans , cnt - 1 )
的缘由时此时使用了y + 1
个CD
因此要减去一个,其余真没啥难度了code
#include <bits/stdc++.h> using namespace std; const int N = 25; int n , m , t , w[N] , ans; inline void dfs( int x , int y , int nt , int cnt ) { if( t < w[x] ) { dfs( x + 1 , y , nt , cnt ); return ; } if( y > m ) { ans = max( cnt - 1 , ans ); return ; } if( x > n ) { ans = max( cnt , ans); return ; } ans = max( cnt , ans ); if( w[x] + nt <= t ) dfs( x + 1 , y , nt + w[x] , cnt + 1 ); else dfs( x + 1 , y + 1 , w[x] , cnt + 1 ); dfs( x + 1 , y , nt , cnt ); return ; } int main() { cin >> n >> t >> m ; for( register int i = 1 ; i <= n ; i ++ ) cin >> w[i]; dfs( 1 , 1 , 0 , 0 ); cout << ans << endl; return 0; }
线性\(dp\),lis问题的四种状况,考码力和细节吧ip
#include <bits/stdc++.h> using namespace std; const int N = 7e5 + 5; int n , a[N] , q[N] , tot ; inline int read() { register int x = 0 , f = 1; register char ch = getchar(); while( ch < '0' || ch > '9' ) { 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() { n = read(); for( register int i = 1 ; i <= n ; a[i] = read() , i ++ ); // 最长上升序列长度 tot = 1 , q[1] = a[1]; for( register int i = 2 ; i <= n ; i ++ ) { if( a[i] > q[ tot ] ) q[ ++ tot ] = a[i]; else *lower_bound( q + 1 , q + 1 + tot , a[i] ) = a[i]; } cout << tot << endl; // 最长降低序列长度 tot = 1 , q[1] = a[1]; for( register int i = 2 ; i <= n ; i ++ ) { if( a[i] < q[ tot ] ) q[ ++ tot ] = a[i]; else *lower_bound( q + 1 , q + 1 + tot , a[i] , greater<int>() ) = a[i]; } cout << tot << endl; // 最长不上升序列长度 tot = 1 , q[1] = a[1]; for( register int i = 2 ; i <= n ; i ++ ) { if( a[i] <= q[ tot ] ) q[ ++ tot ] = a[i]; else *upper_bound( q + 1 , q + 1 + tot , a[i] , greater<int>() ) = a[i]; } cout << tot << endl; // 最长不降低序列长度 tot = 1 , q[1] = a[1]; for( register int i = 2 ; i <= n ; i ++ ) { if( a[i] >= q[ tot ] ) q[ ++ tot ] = a[i]; else *upper_bound( q + 1 , q + 1 + tot , a[i] ) = a[i]; } cout << tot << endl; }
由于是\(noip\)的原题,因此在哪都有,但咱们校\(OJ\)卡常数
因此就要换一种作法
咱们已知秦九韶能够\(O(n)\)的计算出每一个数,那么是否能够优化这个复杂度呢
\[ 设原式为f(x),b=x\mod p \\ \therefore f(x)\equiv f(b) (\mod p) \\ \because f(x) \equiv 0 (\mod p) , \therefore f(b)\equiv 0(\mod p) \]
因此咱们能够先预处理出\(1\dots p-1\)中全部的数,而后对于\(\forall i\in [1,m] f(i)\)咱们判断\(f(i\mod p)\)便可
这样咱们只须要缩小\(p\)就能够下降复杂度,可是若是\(p\)比较小就可能会出现冲突,因此咱们取多个模数便可
根据实测在\(10^5\)取\(4\)个模数是最优的
#include <bits/stdc++.h> using namespace std; const int N = 105 , M = 1e6 + 5 , p1 = 11261 , p2 = 19997 , p3 = 14843 , p4 = 22877; int n , m , a[N] , b[N] , c[N] , d[N] , tot , ans[M]; bool f1[ p1 + 10 ] , f2[ p2 + 10 ] , f3[ p3 + 10 ] , f4[ p4 + 10 ]; inline void read( int & a , int & b , int & c , int & d ) { register int f = 1; register char ch = getchar(); for( ; ch < '0' || ch > '9' ; ( ch == '-' ? f = - 1 : f ) , ch = getchar() ); for( ; ch >= '0' && ch <= '9' ; a = ( ( a << 3 ) % p1 + ( a << 1 ) % p1 + ch - '0' ) % p1 , b = ( ( b << 3 ) % p2 + ( b << 1 ) % p2 + ch - '0' ) % p2 , c = ( ( c << 3 ) % p3 + ( c << 1 ) % p3 + ch - '0' ) % p3 , d = ( ( d << 3 ) % p4 + ( d << 1 ) % p4 + ch - '0' ) % p4 , ch = getchar() ); a *= f , b *= f , c *= f , d *= f ; return ; } inline bool check( int x , int p , int *a ) { int s = a[n]; for( register int i = n - 1 ; i >= 0 ; i -- ) s = ( s * x + a[i] ) % p ; return !s; } inline void work( int p , bool * f , int * a ) { f[0] = !a[0]; for( register int i = 1 ; i < p ; i ++ ) f[i] = check( i , p , a ); return ; } int main() { cin >> n >> m; for( register int i = 0 ; i <= n ; read( a[i] , b[i] , c[i] , d[i] ) , i ++ ); work( p1 , f1 , a ) , work( p2 , f2 , b ) , work( p3 , f3 , c ) , work( p4 , f4 , d ); for( register int i = 1 ; i <= m ; i ++ ) { if( f1[ i % p1 ] && f2[ i % p2 ] && f3[ i % p3 ] && f4[ i % p4 ] ) ans[ ++ tot ] = i; } printf( "%d\n" , tot ); for( register int i = 1 ; i <= tot ; printf( "%d\n" , ans[i] ) , i ++ ); return 0; }
\(Noip\)原题,首先考虑如何知足第一个条件,反向建图,充目标点开始作\(DFS\),把全部到达的点打上标记,这样若是一个点的子节点所有都被打上标记,那么这个点就知足第一条件
第二个条件就是裸的最短路,直接在被标记的点的中跑一遍最短路
#include <bits/stdc++.h> #define PII pair< int, int > #define F first #define S second #define vit vector<int>::iterator using namespace std; const int N = 10005 , INF = 0x7f7f7f7f; int n , m , st , ed , dis[N]; bool vis[N] , can[N]; set< PII > s; vector<int> e[N] , t[N] ; inline int read() { register int x = 0; register char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ch - '0'; ch = getchar(); } return x; } inline void add( int x , int y ) { e[x].push_back(y) , t[y].push_back(x); } inline void dfs( int x ) { can[x] = 1; for( register vit v = t[x].begin() ; v != t[x].end() ; v ++ ) { if( can[*v] ) continue; dfs( *v ); } return ; } inline bool panding( int x ) { for( register vit v = e[x].begin() ; v != e[x].end() ; v ++ ) { if( can[*v] ) continue; return 1; } return 0; } inline void Dijkstra() { for( register int i = 1 ; i <= n ; i ++ ) dis[i] = INF; s.insert( { 0 , st } ) , dis[st] = 0; for( register int u , w; s.size() ; ) { u = s.begin() -> S , s.erase( s.begin() ); if( vis[u] ) continue; vis[u] = 1; if( panding(u) ) continue; if( u == ed ) return ; for( register vit v = e[u].begin() ; v != e[u].end() ; v ++ ) { if( dis[*v] <= dis[u] + 1 ) continue; dis[*v] = dis[u] + 1; s.insert( { dis[*v] , *v } ); } } } int main() { n = read() , m = read(); for( register int x , y ; m >= 1 ; x = read() , y = read() , add( x , y ) , m -- ); st = read() , ed = read(); dfs(ed); Dijkstra(); cout << ( dis[ed] == INF ? -1 : dis[ed] ) << endl; return 0; }
一道搜索题,能够采用一个非正确的算法水过去
咱们判断程序运行的时间,若是接进\(T\)的时候输出当前的最优解,而后直接结束程序
这个代码不能保证正确性,也不能保证复杂度,正确性取决于测评机是速度
但要知道在比赛中,若是数据达到必定规模,你没法继续优化复杂度的状况下,经过这种方式来偏分,对一个就是赚一个
这种方式确定比你直接输出随机数正确性高
#include <bits/stdc++.h> #define exmax( x , y , z ) ( max( x , max( y , z ) ) ) using namespace std; const int N = 33 , INF = 0x7f7f7f7f , ed = 980; int n , a[N] , ans = INF , t1 , t2 , sum; inline void dfs( int t , int s1 , int s2 , int s3 ) { if( exmax( s1 , s2 , s3 ) >= ans ) return ; if( t > n ) { ans = min( ans , exmax( s1 , s2 , s3 ) ); return ; } t2 = clock(); if( t2 - t1 >= ed ) { cout << ans << endl; exit(0); } dfs( t + 1 , s1 + a[t] , s2 , s3 ); dfs( t + 1 , s1 , s2 + a[t] , s3 ); dfs( t + 1 , s1 , s2 , s3 + a[t] ); return ; } int main() { t1 = clock(); cin >> n; for( register int i = 1 ; i <= n ; i ++ ) cin >> a[i]; sort( a + 1 , a + 1 + n , greater<int>() ); dfs( 1 , 0 , 0 , 0 ); cout << ans << endl; return 0; }