1.4 Zustandsmaschinenmodell

Einführung in die Zustandsmaschine:
Fügen Sie hier eine Bildbeschreibung ein

1.Der große Dieb Ah Fu

Ah Fu ist ein erfahrener Dieb. Ah Fu nutzte den dunklen Mond und den starken Wind und plante, heute Abend ein Geschäft in einer Straße zu durchsuchen.

Insgesamt gibt es in dieser Straße NNEs gibt N Geschäfte, von denen jeder etwas Bargeld hat.

Ah Fu erfuhr aus seinen vorherigen Ermittlungen, dass nur dann die Alarmanlage auf der Straße aktiviert wurde, als er zwei benachbarte Geschäfte gleichzeitig durchsuchte und dann die Polizei einschwärmte.

Als Dieb, der Verbrechen immer vorsichtig begeht, ist Ah Fu nicht bereit, das Risiko einzugehen, von der Polizei verfolgt zu werden.

Er wollte wissen, wie viel Bargeld er heute Abend höchstens bekommen könnte, ohne die Polizei zu alarmieren?

Eingabeformat
Die erste Eingabezeile ist eine Ganzzahl TTT , was eine Gesamtzahl vonTTT- Datengruppe.

Für jeden nachfolgenden Datensatz ist die erste Zeile eine Ganzzahl NNN , was darauf hinweist, dass esNNN Geschäfte.

Die zweite Zeile ist NNN durch Leerzeichen getrennte positive ganze Zahlen, die den Bargeldbetrag in jedem Geschäft darstellen.

Der Bargeldbetrag in jedem Geschäft überschreitet nicht 1000 10001000

Ausgabeformat
Geben Sie für jeden Datensatz eine Zeile aus.

Die Zeile enthält eine Ganzzahl, die den Bargeldbetrag darstellt, den Afu erhalten konnte, ohne die Polizei zu alarmieren.

Datenbereich
1 ≤ T ≤ 50, 1≤T≤50,1T50 ,
1 ≤ N ≤ 1 0 5 1≤N≤10^{5}1N1 05

Eingabebeispiel:

2
3
1 8 2
4
10 7 6 14

Ausgabebeispiel:

8
24

Beispielerklärung
Für die erste Reihe von Beispielen wählte Afu den zweiten Laden aus, um ihn zu stehlen, und der Bargeldbetrag, den er erhielt, betrug 8 88

Für die zweite Reihe von Beispielen wählte Afu das erste und das vierte Geschäft zum Diebstahl aus und der erhaltene Bargeldbetrag betrug 10 + 14 = 24 10+14=2410+14=24

1.1 Lösung

Fügen Sie hier eine Bildbeschreibung ein

Fügen Sie hier eine Bildbeschreibung ein
Betrachten Sie nun nur den Zustand der oberen Ebene und nicht den Zustand der oberen beiden Ebenen

Zerlegen Sie
Fügen Sie hier eine Bildbeschreibung ein
das Zustandsmaschinenmodell
Fügen Sie hier eine Bildbeschreibung ein
mithilfe der DP-Analysemethode + Zustandsmaschine

Fügen Sie hier eine Bildbeschreibung ein
Verwenden Sie die Form einer Zustandsmaschine, um schwer auszudrückende Zustände zu trennen

Idee 1
Wir können ein Array als f [ ] f[] definierenf [ ]

f [ i ] f[i]f [ i ] stellt den maximalen Bargeldbetrag dar, den die Familie vor dem Raub erhalten kann.

Dann gibt es zwei Situationen für den Raub unseres ehemaligen I-Hauses:

Der erste Fall: Den i-ten Speicher nicht stehlen
, dann f [ i ] = f [ i − 1 ] f[i]=f[i−1]f [ i ]=f [ ich1 ] ;

Der zweite Fall: Diebstahl des i-ten Speichers
, dann f [ i ] = f [ i − 1 ] + w [ i ] . f[i]=f[i−1]+w[i].f [ i ]=f [ ich1 ]+w [ i ] .

w [i] w[i]w [ i ] stellt das gesamte Bargeld im i-ten Geschäft dar)

Probleme, die sich aus Idee 1 ergeben:
Wenn i − 1 i−1ichLaden 1 wurde ausgeraubt, und Laden IIwurde ebenfalls ausgeraubtIch Familie, das entspricht nicht den Anforderungen der Frage.

Was sollen wir dann tun?

Richtige Methode (Idee 2):

Wir definieren das f-Array als zweidimensional, d. h. f [ ] [ ] f[][]f [ ] [ ]

Wir verwenden ein Array, um zwei Situationen zu speichern: Stehlen oder Nicht-Stehlen.

f [ i ] [ 0 ] f[i][0]f [ i ] [ 0 ] stellt den maximalen Bargeldbetrag dar, der erhalten werden kann, ohne den i-ten Laden zu stehlen;
f [ i ] [ 1 ] f [i][1]f [ i ] [ 1 ] stellt den maximalen Bargeldbetrag dar, der durch den Diebstahl des i-ten Ladens erhalten werden kann.

Dann gibt es drei Situationen:
Fügen Sie hier eine Bildbeschreibung ein
Erklärung:

Die rote Linie im Bild stellt eine mögliche Lösung dar. Sie müssen nicht nach i − 1 i−1 greifenichNr. 1 , und die zweitewerde ich mir nicht schnappenHome i ;
Sie müssen sich nicht diei − 1 i−1ich1 , aber schnapp dir dieIIIch bin zu Hause. Sie können i − 1 i−1
greifenich1 , aber schnapp dir nicht dasIIich Familie;

Dann können wir die Zustandsübergangsgleichung erhalten:

f[i][0] = max(f[i - 1][0], f[i - 1][1]);
f[i][1] = f[i - 1][0] + w[i];
1.2 Code-Implementierung
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 100010,INF = 0x3f3f3f3f;
int n;
int w[N],f[N][2];

int main()
{
    
    
    int T;
    scanf("%d",&T);
    while(T--)
    {
    
    
        scanf("%d",&n);
        for(int i = 1;i <= n;i++)   scanf("%d",&w[i]);
        f[0][0] = 0,f[0][1] = -INF;
        for(int i = 1;i <= n;i++)
        {
    
    
            f[i][0] = max(f[i - 1][0],f[i - 1][1]);
            f[i][1] = f[i - 1][0] + w[i];
        }
        printf("%d\n",max(f[n][0],f[n][1]));
    }
    
    return 0;
}

2. Aktienhandel IV

Gegeben sei eine Länge von NNArray von N , iithim ArrayDie Zahl i stellt die Position einer bestimmten Aktie zum ZeitpunktiiPreis für einen Tag.

Entwerfen Sie einen Algorithmus, um den maximalen Gewinn zu berechnen, den Sie erzielen können. Sie können höchstens kk abschließenk Transaktionen.

HINWEIS: Sie können nicht an mehreren Trades gleichzeitig teilnehmen (Sie müssen Ihre vorherigen Aktien verkaufen, bevor Sie sie erneut kaufen). Ein Kauf und Verkauf wird zu einer Transaktion zusammengefasst.

Eingabeformat
Die erste Zeile enthält die Ganzzahl NNN undkk_k stellt die Länge des Arrays und die maximale Anzahl von Transaktionen dar, die Sie abschließen können.

Die zweite Zeile enthält NNN nicht mehr als10000 10000Eine positive Ganzzahl von 10000 , die das vollständige Array darstellt.

Ausgabeformat
Gibt eine Ganzzahl aus, die den maximalen Gewinn darstellt.

Datenbereich
1 ≤ N ≤ 1 0 5 , 1≤N≤10^{5},1N1 05 ,
1 ≤ k ≤ 100 1≤k≤1001k100
Eingabebeispiel 1:

3 2
2 4 1

Ausgabebeispiel 1:

2

Eingabebeispiel 2:

6 2
3 2 6 5 0 3

Ausgabebeispiel 2:

7

Beispielerklärung
Beispiel 1: Kauf am 1. Tag (Aktienkurs = 2) und Verkauf am 2. Tag (Aktienkurs = 4). Der Gewinn aus dieser Transaktion = 4-2 = 2.

Beispiel 2: Kauf am 2. Tag (Aktienkurs = 2) und Verkauf am 3. Tag (Aktienkurs = 6). Der Gewinn aus dieser Transaktion = 6-2 = 4. Dann kaufen Sie am 5. Tag (Aktienkurs = 0) und verkaufen am 6. Tag (Aktienkurs = 3). Der Gewinn aus dieser Transaktion = 3-0 = 3. Gesamtgewinn 4+3 = 7.

2.1 Lösung

Fügen Sie hier eine Bildbeschreibung ein
Initialisierung: f[0][j][0] = 0, der Rest -INF, da der 0Lagerbestand nicht mehr vorrätig sein muss, muss die Übertragung von dieser Position aus beginnen, um wirksam zu sein.

Hinweis:
Im Prozess der Zustandsmaschine hier kaufen oder verkaufen Sie jede Aktie entweder. Es kann nicht gesagt werden, dass Sie sie kaufen und dann direkt am selben Punkt verkaufen. Dies entspricht nicht dem Zustandsmaschinenmodell Daher kann die obige Übertragungsgleichung Fragen aufwerfen.
Warum kann die Zustandsübertragungsgleichung nicht der folgende Code sein, d. h. eine Transaktion wird nur beim Verkauf berücksichtigt, während der ursprüngliche Code nur beim Kauf als Transaktion betrachtet wird?

f[i][j][0] = max(f[i - 1][j - 1][1] + w[i], f[i - 1][j][0]);
f[i][j][1] = max(f[i - 1][j][0] - w[i], f[i - 1][j][1]);

Schließlich müssen wir zum Ausgangspunkt des Zustandsübergangs zurückkehren. Die erste Aktie hat nur zwei Operationen: Kaufen und Nichtkaufen. Es darf nicht zwei Operationen sein: Verkaufen und Nichtverkaufen. Wenn also die erste Aktie gekauft wird, Es muss entsprechend der Verarbeitung einer Transaktion ausgeführt werden . Andernfalls, wenn der erste Aktienkauf nicht als eine Transaktion behandelt wird, bedeutet dies, dass der Verkauf der ersten Aktie als Transaktion betrachtet wird, was bedeutet, dass eine andere Aktie gekauft wurde, bevor die erste Aktie verkauft wurde. , offensichtlich widersprüchlich.

2.2 Code-Implementierung
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 100010,M = 110,INF = 0x3f3f3f3f;

int n,m;
int w[N];
int f[N][M][2];//状态

int main()
{
    
    
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)   scanf("%d",&w[i]);   
    
    memset(f,-0x3f,sizeof f);
    for(int i = 0;i <= n;i++)    f[i][0][0] = 0;
   
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
        {
    
    
            f[i][j][0] = max(f[i - 1][j][0],f[i - 1][j][1] + w[i]);
            f[i][j][1] = max(f[i - 1][j][1],f[i - 1][j - 1][0] - w[i]);
        }
    
    //枚举一下进行多少次交易
    int res = 0;
    //最后手中一定没货
    for(int i = 0;i <= m;i++)   res = max(res,f[n][i][0]);
    printf("%d",res);
    return 0;
}

3. Aktienhandel V

Gegeben sei eine Länge von NNArray von N , iithim ArrayDie Zahl i stellt die Position einer bestimmten Aktie zum ZeitpunktiiPreis für einen Tag.

Entwerfen Sie einen Algorithmus zur Berechnung des maximalen Gewinns. Sie können so viele Transaktionen wie möglich durchführen (eine Aktie mehrmals kaufen und verkaufen), sofern die folgenden Einschränkungen gelten:

  • Sie können nicht an mehreren Trades gleichzeitig teilnehmen (Sie müssen Ihre vorherigen Aktien verkaufen, bevor Sie sie erneut kaufen).
  • Nach dem Verkauf der Aktie können Sie die Aktie am nächsten Tag nicht mehr kaufen (d. h. die Sperrfrist beträgt 1 Tag).

Eingabeformat
Die erste Zeile enthält die Ganzzahl NNN stellt die Array-Länge dar.

Die zweite Zeile enthält NNN nicht mehr als10000 10000Eine positive Ganzzahl von 10000 , die das vollständige Array darstellt.

Ausgabeformat
Gibt eine Ganzzahl aus, die den maximalen Gewinn darstellt.

Datenbereich
1 ≤ N ≤ 1 0 5 1≤N≤10^{5}1N1 05Eingabebeispiel
:

5
1 2 3 0 2

Ausgabebeispiel:

3

Beispielerklärung
Der entsprechende Transaktionsstatus ist: [Kauf, Verkauf, Sperrfrist, Kauf, Verkauf], die erste Transaktion kann einen Gewinn erzielen 2 − 1 = 1 2-1 = 121=1 beträgt der Gewinn aus der zweiten Transaktion2 − 0 = 2 · 2-0 = 220=2 , Gesamtgewinn1 + 2 = 3 1+2 = 31+2=3

3.1 Lösung

Fügen Sie hier eine Bildbeschreibung ein
Initialisierung: f[0][2] = f[0][1] = 0,f[0][0] = -INF, da der 0. Bestand nicht mehr vorrätig sein muss und die Übertragung von dieser Position aus beginnen muss, um wirksam zu sein.

3.2 Code-Implementierung
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 100010,INF = 0x3f3f3f3f;

int n;
int w[N];
int f[N][3];

int main()
{
    
    
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)   scanf("%d",&w[i]);
    f[0][0]  = - INF;
    f[0][2] = f[0][1] = 0;
    
    for(int i = 1;i <= n;i++)
    {
    
    
        f[i][0] = max(f[i - 1][0],f[i - 1][2] - w[i]);
        f[i][1] = f[i - 1][0] + w[i];
        f[i][2] = max(f[i - 1][1],f[i - 1][2]);
    }
    
    cout << max(f[n][1],f[n][2]) <<endl;
    
    return 0;
}

4. Entwerfen Sie ein Passwort

Sie müssen nun ein Passwort SS entwerfenS ,SSS muss Folgendes erfüllen:

SSDie Länge von S beträgtNNN
SSS enthält nur englische Kleinbuchstaben;
SSS enthält nicht die TeilzeichenfolgeTTT ;
zum Beispiel:abc abcab cabcde abcdeab c d eabcde abcdeTeilzeichenfolge von ab c d e , abd abdab d ist nichtabcde abcdeTeilzeichenfolge von ab c d e .

Wie viele verschiedene Passwörter können die Anforderungen erfüllen?

Da die Antwort sehr umfangreich sein wird, geben Sie die Antwort bitte modulo 1 0 9 + 7 10^{9}+7 aus1 09+Der Rest von 7 .

Eingabeformat:
Geben Sie in der ersten Zeile die Ganzzahl NN einN stellt die Länge des Passworts dar.

In der zweiten Zeile wird die Zeichenfolge TT eingegebenT ,TTT enthält nur Kleinbuchstaben.

Ausgabeformat:
Geben Sie eine positive Ganzzahl aus, die die Gesamtzahl der Lösungen modulo 1 0 9 + 7 10^{9}+7 angibt1 09+Das Ergebnis nach 7 .

Datenbereich
1 ≤ N ≤ 50, 1≤N≤50,1N50 ,
1 ≤ ∣ T ∣ ≤ N , ∣ T ∣ 1≤|T|≤N,|T|1T N , T istTTDie Länge von T.

Eingabebeispiel 1:

2
a

Ausgabebeispiel 1:

625

Eingabebeispiel 2:

4
cbc

Ausgabebeispiel 2:

456924
4.1 Lösung des Problems (dieses Problem ist problematischer und kombiniert Automaten und KMP)

Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein

Warum ist eine solche Landesvertretung machbar?
Denn SSDer neunteim S- ArrayEs gibt 26 26 in n Ziffern26 Kleinbuchstaben, passend inTTDie Position in T muss vorhanden sein (da es keine Übereinstimmung gibt, ist die übereinstimmende Position0 0)0 ),
also setzen Sie allef [ n ] [ 0 m − 1 ] f[n][0~m-1]f [ n ] [ 0 m 1 ] Zur Gesamtzahl der Pläne addieren

4.2 Code-Implementierung
#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=55,mod=1e9+7;

int f[N][N],ne[N];
char str[N];//子串

int main()
{
    
    
    int n,m;
    cin>>n>>str+1;
    m=strlen(str+1);

    for(int i=2,j=0;i<=m;i++)//求出ne数组(kmp模板)
    {
    
    
        while(j&&str[j+1]!=str[i]) j=ne[j];
        if(str[j+1]==str[i]) j++;
        ne[i]=j;
    }

    f[0][0]=1;//已经匹配了0位,且匹配的子串的位置是0时的方案数为1;(初始化)
    for(int i=0;i<n;i++)//枚举密码位
     for(int j=0;j<m;j++)//把第i位密码匹配到的子串位置都枚举一遍
     //j表示第i位密码匹配到的位置,因为不能包含子串,所以不能匹配到m这个位置
      for(char k='a';k<='z';k++)//把第i+1所有可能的字母都枚举一遍
       {
    
    
           //匹配过程:寻找当第i+1的位置是k时,并且密码已经生成了第i位,匹配的子串的位置是j时,能跳到哪个位置
           int u=j;
           while(u&&str[u+1]!=k) u=ne[u];
           if(str[u+1]==k) u++;

           if(u<m) f[i+1][u]=(f[i+1][u]+f[i][j])%mod;
           //因为是从f[i][j](i+1的位置为k)跳到f[i+1][u]这个位置,所以f[i+1][u]=f[i+1][u]+f[i][j];
           /*
           注:可能存在重边,因为j不同但ne[j]是相同的,并且k是相同的,所以此时
           f[i][j1]和f[i][j2]跳到的位置是一样的(k相同,ne[j1]=ne[j2])
           */
       }

    int res=0;
    for(int i=0;i<m;i++) res=(res+f[n][i])%mod;
    //将所有的方案数加起来即为总方案数
    printf("%d",res);

    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/m0_51366201/article/details/132611475
Recomendado
Clasificación