[45] (多校聯訓) A層衝刺NOIP2024模擬賽05

HaneDaniko發表於2024-10-11
這是什麼

午休,大黃突然走進來

大黃:閃電特效!

其他人:?

大黃:5k!

其他人:???

大黃:

【閃電特效】【閃電特效】
男人中的男人
【閃電特效】【閃電特效】
雄性中的雄性
【閃電特效】【閃電特效】
巔峰!
【閃電特效】【閃電特效】

A.好數

簡單變形一下

\[f_i+f_j+f_k=c \]

\[f_j+f_k=c-f_i \]

然後 \(f_j+f_k\) 是可以 \(n^2\) 維護的,所以你直接把這玩意丟桶裡

直接在桶裡查 \(c-f_i\) 就行了

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[5001];
int cnt2[1000001];
const int dx=500000;
int ans,ans2;
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;++i){
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<=n;++i){
            for(int j=1;j<=i-1;++j){
                if(cnt2[a[i]-a[j]+dx]){
                    ans2++;
                    break;
                }
            }
        for(int k=1;k<=i;++k){
            cnt2[a[i]+a[k]+dx]=true;
        }
    }
    cout<<ans2;
}

B.SOS 字串

賽時打的記搜不夠優,所以沒怎麼拿分

我的思路是記一下字串裡有多少萬用字元,最後快速冪一塊乘起來,賽後發現自己就像若智一樣,這麼寫既浪費時間又拖慢記憶化

所以,設 \(f_{i,0/1/2,k}\) 表示當前考慮到第 \(i\) 位,在最近的一個 SOS 中未填(\(0\)),填到第一個 S\(1\)),填到 O ,並且已經填完了 \(k\)SOS 的方案數,直接按這個思路轉移即可

注意點

  • 這題卡掉了 map 的記
  • \(k\ge 3\) 的情況本質是一樣的,所以不要再去考慮 \(k\gt 3\) 的情況了,轉移的時候直接對 \(3\)\(\min\)

分討都在註釋裡了

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=1e9+7;
int n;
int ans[]={
0,
//0
0,0,0,0,0,0,0,0,1,104,6757,351205,15973496,664272712,899139165,727408931,230839283,110517859,10938323,18380962,801591834,538331878,360540447,210225942,551547105,929157669,272821968,705926995,775855957,92872414,973270409,391860935,335059301,85671406,897860651,44139736,589503918,625697165,907940909,65840028,296877522,118994829,791306555,545227129,339582817,556088554,498324683,790874686,448130225,415804878,265383931,350869320,508306396,230852520,207518131,393727895,10918291,217898849,356629754,725800340,721470986,818807886,418275274,98166057,166836105,700350963,284803896,926512861,894412347,395302972,592929019,126921505,647951981,929483993,943743437,633413084,615394211,839148006,505351030,635923265,581764455,628567567,602039917,894182098,22633948,459519338,392370752,266609453,230295067,470625000,553777871,371352394,924404107,267364811,494994623,656969894,411339471,219584748,278697715,
//1-99
386050963,938717640,475120605,760806437,753435202,314937563,851110504,797356893,245785631,262365753,833638573,356358070,487921967,794091475,326352338,473729558,565259085,171901369,335540820,814721033,161257365,217687425,155138438,808186780,386518022,83983404,717178046,78856463,235246882,499975775,733374510,215560962,110112138,900818712,197816052,679749741,695794560,543244371,289768441,371534780,751829883,510022775,825226346,407146882,671249767,392207831,889684111,972461673,42143586,173024277,930675066,714500895,313370867,972865022,223928126,923599447,178339933,889909549,40600138,975842829,849125694,668460497,952095956,598470711,655030486,322257610,772694338,624583367,4058244,987656118,585739412,576086511,325923294,813523092,122889315,110009872,706599969,267933649,400120157,886092645,943382227,712297353,218809367,496788446,84125031,637155241,142014530,438296963,902423764,422839788,724584421,920976540,92270597,170789534,937908052,738236019,394787814,710269016,541613082,88290832,325997693
//100-200
};
inline int power(int a,int t){
    int base=a,ans=1;
    while(t){
        if(t&1){
            ans=ans*base%p;
        }
        base=base*base%p;
        t>>=1;
    }
    return ans;
}
int f[1000001][4][5];
int dfs(int now,int sta,int soscnt){
    if(now>n){
        return (soscnt>=3)%p;
    }
    if(f[now][sta][soscnt]){
        return f[now][sta][soscnt];
    }
    int res=0;
    if(sta==2){
        res=(res+dfs(now+1,0,soscnt))%p;   //O
        res=(res+dfs(now+1,0,soscnt==3?3:soscnt+1))%p;   //S
        res=(res+24*dfs(now+1,0,soscnt))%p;   //*
    }
    if(sta==1){
        res=(res+dfs(now+1,2,soscnt))%p;   //O
        res=(res+dfs(now+1,1,soscnt))%p;   //S
        res=(res+24*dfs(now+1,0,soscnt))%p;   //*
    }
    if(sta==0){
        res=(res+dfs(now+1,0,soscnt))%p;   //O
        res=(res+dfs(now+1,1,soscnt))%p;   //S
        res=(res+24*dfs(now+1,0,soscnt))%p;   //*
    }
    return f[now][sta][soscnt]=res%p;
}
signed main(){
    freopen("sos.in","r",stdin);
    freopen("sos.out","w",stdout);
    cin>>n;
    cout<<dfs(1,0,0);
}

P4141.消失之物

直接做 \(q\) 遍 DP 的話,有很多都是重複計算的

考慮怎麼才能只做一遍 DP

我們在做 DP 的時候,如果選了 \(i\),轉移為

f[j]+=f[j-w[i]]

所以當我們不選 \(i\) 的時候,從答案裡減掉的貢獻即為

f[j]-=f[j-w[i]]

乍一看不是很對,實際上直接無腦減確實是不對的,但是隻要滿足轉移和撤銷是反著來的,那麼,後更新的就會先被撤銷,那麼就一定是正確的了(當然,如果你開兩維就可以很好地避免動這個腦子)

為什麼要在最終狀態上撤?其實在這裡撤和在轉移到 \(i\) 撤是一樣的,雖然答案增加了,但是兩個版本的答案的差並沒變

#include<bits/stdc++.h>
using namespace std;
const int p=10000;
int n,m;
int w[2001];
int f[2001];
int g[2001];
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&w[i]);
    }
    memset(f,0,sizeof f);
    f[0]=1;
    for(int i=1;i<=n;++i){
        for(int j=m;j>=0;--j){
            if(j>=w[i]) f[j]=(f[j]+f[j-w[i]])%p;
        }
    }
    for(int i=1;i<=n;++i){
        memcpy(g,f,sizeof f);
        for(int j=w[i];j<=m;++j){
            g[j]=(g[j]-g[j-w[i]]+p)%p;
        }
        for(int j=1;j<=m;++j){
            cout<<g[j]%10;
        }
        cout<<'\n';
    }
}
二維寫法
#include<bits/stdc++.h>
using namespace std;
const int p=10000;
int n,m;
int w[2001];
int f[2001][2001];
int g[2001];
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&w[i]);
    }
    memset(f,0,sizeof f);
    f[0][0]=1;
    for(int i=1;i<=n;++i){
        for(int j=0;j<=m;++j){
            if(j>=w[i]) f[i][j]=(f[i][j]+f[i-1][j-w[i]])%p;
            f[i][j]=(f[i][j]+f[i-1][j])%p;
        }
    }
    for(int i=1;i<=n;++i){
        memcpy(g,f[n],sizeof f[n]);
        for(int j=w[i];j<=m;++j){
            g[j]=(g[j]-g[j-w[i]]+p)%p;
        }
        for(int i=1;i<=m;++i){
            cout<<g[i]%10;
        }
        putchar('\n');
    }
}

C.集訓營的氣球

和上一個題類似,這個題無非就是加一個重新 DP 的過程

\(f_i\) 表示有 \(i\) 個人選了強制選的那個,正難則反,我們可以求出不合法的方案書,再用總方案去減

總方案很好求,\(tot=\prod\limits(a_i+b_i)\),剩下的不合法方案數直接套模板

總方案數的修改 \(tot'=\frac{tot'}{a_i\times b_i}\times(a_i'\times b_i')\)

揹包的轉移

\[f_j=f_{j-1}\times a_i+f_j\times b_i \]

(這個轉移就是考慮到當前人,他選擇 \([1,a_i]\) 內的任意一個就會貢獻一個強制選,否則不會)

撤銷

無非就是除以原來的方案數,乘上現在的方案數

除以原來的方案數

\[f_i=\frac{f_i-f_{i-1}\times a_p}{b_p} \]

乘上現在的方案數,和前面轉移是一樣的,這就是撤銷後的恢復操作

要注意的是 \(f_0\) 作為起始值需要單獨轉移

除法直接用逆元處理即可

\(p\) 為修改位置)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=1e9+7;
int power(int a,int t){
    int base=a,ans=1;
    while(t){
        if(t&1){
            ans=ans*base%p;
        }
        base=base*base%p;
        t>>=1;
    }
    return ans;
}
int a[1000001],b[1000001];
/* not satisfied the request

 f_i record the number that has f_i people choose balloon
 
 ans = tot - sum{f_i} */
int f[21];
int n,c,q;
int tot;
signed main(){
    freopen("balloon.in","r",stdin);
    freopen("balloon.out","w",stdout);
    scanf("%lld %lld",&n,&c);
    for(int i=1;i<=n;++i){
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<=n;++i){
        scanf("%lld",&b[i]);
    }
    tot=f[0]=1;
    // do dp at first status
    for(int i=1;i<=n;++i){
        for(int j=c-1;j>0;--j){
            f[j]=(f[j-1]*a[i]+f[j]*b[i])%p;
            /* f the ith people don't choose,
                then there's f_j to f_j,
                otherwise f_{j-1} to f_j*/
        }
        f[0]=(f[0]*b[i])%p;
        /*
        still nobody choose
        */
        tot=(tot*(a[i]+b[i]))%p;
    }
    scanf("%lld",&q);
    while(q--){
        int id,x,y;
        scanf("%lld %lld %lld",&id,&x,&y);
        tot=tot*power(a[id]+b[id],p-2)%p*(x+y)%p;
        /*cal the new tot*/
        int inv=power(b[id],p-2);
        f[0]=f[0]*inv%p;
        /*cal the new f_0*/
        for(int i=1;i<=c-1;++i){
            f[i]=(f[i]-f[i-1]*a[id]%p+p)*inv%p;
        }
        /*undo the dp*/
        for(int i=c-1;i>0;--i){
            f[i]=(f[i-1]*x+f[i]*y)%p;
        }
        /*redo the dp*/
        f[0]=f[0]*y%p;
        a[id]=x;b[id]=y;
        int ans=tot;
        for(int i=0;i<=c-1;++i){
            ans=(ans-f[i]+p)%p;
        }
        cout<<ans<<'\n';
    }
}
推歌

ギャンビット 雄之助feat.初音未來

ショーケース

固定された姿のままで

悲しむマネキンな自分の

提唱する感傷など

投げ捨てろ

還元なき逃走には

リスクが付き物

結局はあいつらが

嫌いなだけなのさ

関係ない人も

敵に見えてたんだ

Fighting back 依存気味の

借り木を取り除いて

橫やりばかりな

妄執へと言い聞かせる

Dancing Doll 終わるのには

早いと気付けたなら

踴り続ける

その足で蹴り飛ばせ

力の限り

Face is handmade

このハッタリ堪えがたい

Nightmare maze

性別や姿がどうしたんだ

苦しむPrideたちがEnemyは

ほんの一部だけだと指を差す

結局は知って欲しい

火打ちを奪われて

消えかけの意志で

當たり散らした

本當は何回も

思ったことがある

取り返す勇気と

自信さえあればとずっと

乾坤一擲

推して參れ

Free Phase

Don't come back here

Don't come back here

逆を向いた月が

夜闇に呑まれようと

鋭く尖らせて

Gambit 犠牲の上

目覚めた今があれば

あらゆる過去など

餌にしてもお釣りがくる

Fighting back 塗り潰した

切り目を引き直せ

感情は渡さない

あいつらに渡さない
這是什麼

huge on the front

i can't view a beautiful laopo

相關文章