GalaxyOJ-945 (逆向思維+去重優化)

題目

Problem 945: 數列的祕密
Time Limit: 1000 ms Memory Limit: 262144 KB

Problem Description

WSW最近在研究數列,他需要知道在他所研究的數列中,最大的數是多少(Max),最小的數是多少(Min),最大的數的最小的數次冪是多少(Max^Min),所有數的乘積是多少。
要知道,這樣的問題是肯定難不倒WSW的。但是,最近WSW突發奇想,想要研究下這個數列的更深層的性質,所以他決定不斷的從這個數列中刪去一些數,每次刪除後都研究下當前數列。由於數列項數很大,這給WSW帶來了很大的麻煩,於是WSW請你幫他寫一個程序,來完成下列操作。
1. D x:表示從數列中刪除x,保證原數列中一定會有x。(注意這裏是如果數列中有多個x,那麼就要先把x全部刪掉,如果某個x在D的時候以前已經被D過了,請自動忽略這一次的D)
2. B:輸出當前數列中的最大數,保證數列不爲空。
3. S:輸出當前數列中的最小數,保證數列不爲空。
4. M:輸出Max^Min 除以317847191 的餘數,其中Max 爲當前數列中的最大數,Min 爲當前數列中的最小數,保證數列不爲空。
5. T:輸出數列中所有數的乘積除以317847191 的餘數,保證數列不爲空。

Input

共M+2 行
第1 行:兩個正整數N,M,N 表示初始數列的長度,M 表示操作數。
第2 行:N 個正整數,第i 個數表示初始數列中的第i 項Ai,數列中有可能會有相同的數。
第3~M+2 行:每行表示一個操作,具體格式參見題目描述。

對於所有數據N<=1,000,000, M<=1,000,000, Ai<=100,000,000

Output

每行一個數,分別表示每個操作的結果(D x 操作不需要有輸出)。

Sample Input

3 6
2 6 9
M
D 9
B
S
M
T

Sample Output

81
6
2
36
12

分析

  • 第一想到線段樹,不過發現空間會炸……
  • 後來發現都是對於整個數組的操作,可以想想一次掃過,由於模數不是質數,可以想到倒着做。
  • 再去個重纔不超時……

程序

#include <cstdio>
#include <algorithm>
#define N 1000005
#define Ha 317847191
#define X q[i].x
typedef long long ll;
using namespace std;
struct que{char Q;ll x,y;} q[N];
ll i,n,m,k,a[N],S[N],F[N],num,Ans=1,Min=2147483647,Max=-2147483647;
char s[10];

ll ksm(ll xx,ll yy){
    long long x=xx,y=yy,ret=1;
    for (; y; y>>=1,x=(x*x)%Ha)
        if (y&1) ret=(ret*x)%Ha;
    return (ll)ret;
}

int main(){
    scanf("%lld%lld",&n,&m);
    for (i=1; i<=n; i++) scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    for (i=1; i<=n; i++) if (a[i]!=a[i-1]) S[++num]++; else S[num]++;
    unique(a+1,a+n+1);

    for (i=1; i<=m; i++){
        q[i].Q=(scanf("%s",s),s[0]);
        if (s[0]=='D'){
            scanf("%lld",&X);
            k=lower_bound(a+1,a+num+1,X)-a;
            if (!F[k]) F[k]=i;
        }
    }

    for (i=1; i<=num; i++) if (!F[i]) Ans=(Ans*ksm(a[i],S[i]))%Ha,Min=min(Min,a[i]),Max=max(Max,a[i]);

    for (i=m; i; i--){
        if (q[i].Q=='D'){   //添加 x 
            k=lower_bound(a+1,a+num+1,X)-a;
            if (F[k]!=i) continue;
            Ans=(Ans*ksm(q[i].x,S[k]))%Ha;
            Min=min(Min,X);
            Max=max(Max,X);
        }
        if (q[i].Q=='B'){   //輸出最大值 
            q[i].y=Max;
        }
        if (q[i].Q=='S'){   //輸出最小值 
            q[i].y=Min;
        }
        if (q[i].Q=='M'){   //Max^Min
            k=ksm(Max,Min);
            q[i].y=k;
        }
        if (q[i].Q=='T'){   //輸出乘積 
            q[i].y=Ans;
        }
    }

    for (ll i=1; i<=m; i++) if (q[i].Q!='D') printf("%lld\n",q[i].y);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章