2020-2021 ACM-ICPC Latin American Regional Programming Contest K. Keylogger (dp,前綴和)


  • 題意:你的鍵盤有\(k\)個按鍵,矩陣\(T_{i,j}\),表示第\(i\)個鍵和第\(j\)個鍵之間的輸入頻率,並帶有一個\(L\)的修正,\(T\)的每一行都是非遞減的,現在你忘了你的密碼,但是你知道你密碼的相鄰兩個字符的輸入頻率,你需要構造一個序列,這個序列需滿足\(T_{S_i,S_{i+1}}-L \le P_i \le T_{S_iS_{i+1}}+L\),問你一共可以構造多少可能的序列並對\(10^9+7\)取模。

  • 題解:對於\(P_1\),我們要現在\(T\)中找一個合法的\({i,j}\),那么對於\(P_2\),我們就只能考慮\(j,x\),也就是說第一個位置必須是\(j\),那這很明顯是可以狀態轉移的,所以這題我們考慮dp。比如說對於\(P_1\)我們找到了\(i,j\),那么\(P_2\)的貢獻之一就可以由\(i,j\)轉移而來,但是不好寫,我們反着來,先找\(P_n\),因為這樣如果我們有合法的位置,因為上一層算過了,就能直接轉移到這一層來。具體轉移就是看每一行,二分找一個滿足\(T_{S_i,S_{i+1}}-L \le P_i \le T_{S_iS_{i+1}}+L\)的區間,說明我們可以從區間內的上一層的這些行轉移過來。設\(dp[i][j]\)表示第\(P_i\)個間隔,第\(j\)行的所有可能序列數,假如\(pos1,pos2\)分別表示第\(j\)行合法的區間的左端點和右端點,所以有:\(dp[i][j]=\sum_{k=pos1}^{pos2}dp[i-1][k]\).這個復雜度是\(O(k)\)的,但因為區間是連續的所以可以用前綴和優化,操作之后\(dp[i][j]\)表示第\(P_i\)個間隔,前\(j\)行的所有可能序列數。

  • 代碼:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    int k,L;
    int T[770][770];
    int n;
    int P[N];
    ll dp[100010][800];
    
    int main() {
        scanf("%d %d",&k,&L);
        for(int i=1;i<=k;++i){
            for(int j=1;j<=k;++j){
                scanf("%d",&T[i][j]);
            }
        }
        scanf("%d",&n);
        for(int i=1;i<n;++i){
            scanf("%d",&P[i]);
        }
        for(int i=1;i<=k;++i) dp[n][i]=i;
        for(int i=n-1;i>=1;--i){
            for(int j=1;j<=k;++j){
                dp[i][j]=dp[i][j-1]; //前綴和
                int pos1=upper_bound(T[j]+1,T[j]+1+k,P[i]+L)-T[j];
                int pos2=lower_bound(T[j]+1,T[j]+1+k,P[i]-L)-T[j];
                ll res1,res2;
                res1=dp[i+1][pos1-1];
                res2=dp[i+1][pos2-1];
                dp[i][j]=(dp[i][j]+res1-res2+mod)%mod;
            }
        }
        printf("%lld\n",dp[1][k]);
        return 0;
    }
    
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM