luogu 題目選作

P1019 單詞接龍

往年的\(noip\)原題,純搜索吧,沒啥可講的,直接暴力枚舉,暴力判斷就行c++

沒有必要每次都存一個很大的字符串,只要存當前的字符串就好了算法

每一個字符串能夠用兩次數組

不能包含關係。。。好像也沒啥了吧優化

#include <bits/stdc++.h>
using namespace std;


const int N = 23;
int n , ans = -1 , v[N] ;
string str[N];

inline int check( string s1 , string s2)
{
    register bool flag;
    for( register int i = 1 ; i < min( s1.size() , s2.size() ) ; i ++ )
    {
        flag = 1;
        for( register int j = 0 ; j < i && flag ; j ++ )
        {
            if( s1[s1.size() - i + j ] != s2[j] ) flag  = 0;
        }
        if( flag ) return i;
    }
    return 0;
}

inline void dfs( string cur , int x )
{
    ans = max( ans , x );
    for( register int i = 1 , k ; i <= n ; i ++ )
    {
        if( v[i] >= 2 ) continue;
        k = check( cur , str[i] );
        if( k )
        {
            v[i] ++;
            dfs( str[i] , x + str[i].size() - k );
            v[i] --;
        }
    }
    return ;
}

int main()
{
    cin >> n;
    for( register int i = 1 ; i <= n + 1 ; i ++ ) cin >> str[i];
    dfs( ' ' + str[ n + 1 ] , 1 );
    cout << ans << endl;
    return 0;
}

P1510 精衛填海

這也是一個經典的揹包問題,揹包求最小費用spa

f[i][j]表示前\(i\)個物品用了\(j\)的體力所能填滿的最大空間,顯然滾動數組優化一維空間code

而後枚舉一下體力,找到最早填滿所有體積的一個便可ip

簡單分析一下,當花費的體力增長時,所填滿的體積保證不會減少,知足單調性ci

二分查找會更快字符串

#include<bits/stdc++.h>
using namespace std;


const int N = 10005;
int n , V , power ,f[N] , use;
bool flag = 0;

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()
{
    V = read() , n = read() , power = read();
    for( register int i = 1 , v , w ; i <= n ; i ++ )
    {
        v = read() , w = read();
        for( register int j = power ; j >= w ; j -- ) f[j] = max( f[j] , f[ j - w ] + v );
    }
    use = lower_bound( f + 1 , f + 1 + power , V ) - f;
    if( f[use] >= V ) printf( "%d\n" , power - use );
    else puts("Impossible");
    return 0;
}

P2918 買乾草Buying Hay

相似P1510精衛填海,不過這是徹底揹包稍做修該便可get

不過要注意f[need]並不是最優解,由於能夠多買點,只要比須要的多便可

#include <bits/stdc++.h>
using namespace std;

const int N = 505005 , INF = 0x7f7f7f7f;
int n , need , f[N] , ans = INF ;


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() , need = read();
    memset( f , INF , sizeof(f) ) , f[0] = 0;
    for( register int i = 1 , w , v ; i <= n ; i ++ )
    {
        v = read() , w = read();
        for( register int j = v ; j <= need + 5000; j ++ ) f[j] = min( f[j] , f[ j - v ] + w ) ;
    }
    for( register int i = need ; i <= need + 5000 ;  i ++ ) ans = min( ans , f[i] );
    cout << ans << endl;
    return 0;
}

P2312 解方程

\(noip\)的原題,由於Luogu跑的比較快,因此能夠用非正確算法過這道題

對於讀入進來的數咱們能夠取一個模,爲何呢由於一個數等於0那麼這個數模一個數也等於0

可是模一個數等於0的數可不必定等於0,爲了儘量的避免這種狀況,要儘量的採用一個大質數,質數越大,越不容易出現問題

而後在用秦九韶算法能夠\(O(n)\)的算出結果,因此枚舉每個數\(O(n)\)的判斷便可,因此總複雜度\(O(nm)\)

#include <bits/stdc++.h>
#define LL long long
using namespace std;


const int N = 105 , M = 1e6 + 5 , p = 1e9+7;
int n , m , tot , ans[M];
LL a[N];

inline void read( LL & a )
{
    register LL 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 ) % p + ( a << 1 ) % p + ch - '0' ) % p , ch = getchar() );
    a *= f ;
    return ;
}

inline bool check( LL x )
{
    register LL s = a[n];
    for( register int i = n - 1 ; i >= 0 ; i -- ) s = ( s * x + (LL)a[i] ) % p ;
    return !s;
}


int main()
{
    cin >> n >> m;
    for( register int i = 0 ; i <= n ; read( a[i] ) , i ++ );
    
    for( register int i = 1 ; i <= m ; i ++ )
    {
        if( check( i ) ) ans[ ++ tot ] = i;
    }
    
    printf( "%d\n" , tot );
    for( register int i = 1 ; i <= tot ; printf( "%d\n" , ans[i] ) , i ++ );
    return 0;
}

P2296 尋找道路

\(Noip\)原題,首先考慮如何知足第一個條件,反向建圖,充目標點開始作\(DFS\),把全部到達的點打上標記,這樣若是一個點的子節點所有都被打上標記,那麼這個點就知足第一條件

第二個條件就是裸的最短路,直接在被標記的點的中跑一遍最短路

#include <bits/stdc++.h>
#define PII pair< int, int >
#define F first
#define S second
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 auto v : t[x] )
    {
        if( can[v] ) continue; 
        dfs( v );
    }
    return ;
}

inline bool panding( int x )
{
    for( register auto v : e[x] )
    {
        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 auto v : e[u] )
        {
            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;
}
相關文章
相關標籤/搜索