2019.8.5中山紀中提高A組題解

矩陣遊戲

【NOIP提高組A】題目描述

在這裏插入圖片描述

Input
在這裏插入圖片描述

Output
在這裏插入圖片描述

Sample Input

Sample Input1
3 4 4
R 2 4
S 4 1
R 3 2
R 2 0

Sample Input2
2 4 4
S 2 0
S 2 3
R 1 5
S 1 3

Sample Output

Sample Output1
94

Sample Output2
80

Data Constraint
在這裏插入圖片描述

題解

最樸素的算法O(n2)O(n^{2})是過不了的。
然後發現了這道題操作的順序是不影響最後的結果的,所以對每行每列的操作可以一起存下來。
既是定義H[i]H[i]爲第ii行上的數變成了原來的ii倍,L[i]L[i]爲第ii列上的數變成了原來的ii
顯然H[],L[]H[],L[]開始全爲1,然後隨着輸入更新就行了。
並且我們可以通過一個數的座標算出它的值。
num[i][j]=(i1)m+jnum[i][j]=(i-1)*m+j
ans=i=1nj=1mnum[i][j]H[i]L[j]ans=\sum_{i=1}^{n}\sum_{j=1}^{m}num[i][j]*H[i]*L[j]
ans=i=1nj=1m((i1)m+j)H[i]L[j]ans=\sum_{i=1}^{n}\sum_{j=1}^{m}((i-1)*m+j)*H[i]*L[j]
ans=i=1nj=1m((i1)mH[i]L[j]+jH[i]L[j])ans=\sum_{i=1}^{n}\sum_{j=1}^{m}((i-1)*m*H[i]*L[j]+j*H[i]*L[j])
ans=j=1mL[j]i=1n(i1)mH[i]+i=1nH[i]j=1mjL[j]ans=\sum_{j=1}^{m}L[j]\sum_{i=1}^{n}(i-1)*m*H[i]+\sum_{i=1}^{n}H[i]\sum_{j=1}^{m}j*L[j]

所以先分別算出i=1n(i1)mH[i]\sum_{i=1}^{n}(i-1)*m*H[i]j=1mjL[j]\sum_{j=1}^{m}j*L[j]然後再分別統計答案再求和就行了

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long LL;
using namespace std;
const int MAXN=int(1e6+5);
#define mod int(1e9+7)
LL n,m,k;
LL x,y;
LL H[MAXN],L[MAXN];
LL S0,S1;
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    char s[10];
    scanf("%lld%lld%lld",&n,&m,&k);
    LL x,y;
    for(LL i=1;i<=n;i++)
        H[i]=1;
    for(LL i=1;i<=m;i++)
        L[i]=1;
    while(k--) {
        scanf("%s%lld%lld",s,&x,&y);
        if(s[0]=='R') H[x]=H[x]*y%mod;
        else L[x]=L[x]*y%mod;
    }
    for(LL i=1;i<=n;i++)
        S0=(S0+(i-1)*m%mod*H[i]%mod)%mod;
    for(LL i=1;i<=m;i++)
        S1=(S1+i*L[i]%mod)%mod;
    LL ans=0;
    for(LL i=1;i<=m;i++)
        ans=(ans+S0*L[i]%mod)%mod;
    for(LL i=1;i<=n;i++)
        ans=(ans+S1*H[i]%mod)%mod;
    printf("%lld",ans);
}

【NOIP提高組A】跳房子

題目描述

在這裏插入圖片描述

Input

在這裏插入圖片描述
Output
在這裏插入圖片描述

Sample Input

4 4
1 2 9 3
3 5 4 8
4 3 2 7
5 8 1 6
4
move 1
move 1
change 1 4 100
move 1

Sample Output
4 2

1 3
1 4

Data Constraint
在這裏插入圖片描述

題解

受到中山紀中講題時常不喜歡給正解的影響(雖然這道題給了),好吧我太菜了,講一下我考場上的思路。因爲k&lt;=109k&lt;=10^{9},所以我們需要找到一個環使kk變小。再看看找環這個思路雖然容易被卡,但是還算可做,所以就決定直接找環。
具體實現上爲了減少在更改後重新找環的過程,我們把一堆changechange弄成一塊,一堆movemove看成一塊,然後每次更改後的第一次movemove重新找環就行了,據說是可以過85因爲數據太水了沒有專門卡這個(其實可以卡成O(n2Q)O(n^{2}Q)

代碼

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN=int(2e3+5);
int n,m,Qm;
int a[MAXN][MAXN];
bool vis[MAXN][MAXN];
struct node {
    int x,y;
    node() {};
    node(int X,int Y):x(X),y(Y){}
}t[5];
vector<node>Q;
int hug;
node Up(node u) {return node((u.x+n-2)%n+1,u.y%m+1);}
node Mid(node u) {return node(u.x,u.y%m+1);}
node Down(node u) {return node(u.x%n+1,u.y%m+1);}
bool cmp(node p,node q) {
    return a[p.x][p.y]>a[q.x][q.y];
}
void Build(node u) {
    t[1]=Up(u),t[2]=Mid(u),t[3]=Down(u);
    sort(t+1,t+4,cmp);
    node nx=t[1];
    if(vis[nx.x][nx.y]) {
        for(int i=0;i<Q.size();i++)
            if(Q[i].x==nx.x&&Q[i].y==nx.y)
                hug=i;
        return;
    }
    vis[nx.x][nx.y]=1;
    Q.push_back(nx);
    Build(nx);
}
int main()
{
    freopen("jump.in","r",stdin);
    freopen("jump.out","w",stdout);
    node now=node(1,1);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    scanf("%d",&Qm);
    char s[10];
    int x,y,z,k;
    int d=0;
    bool f=1;
    for(int i=1;i<=Qm;i++) {
        scanf("%s",s);
        if(s[0]=='c') {
            scanf("%d%d%d",&x,&y,&z);
            a[x][y]=z;
            f=1;
        }
        else {
            scanf("%d",&k);
            if(f) {
                while(Q.size()!=0) {
                    node q=Q.back();
                    Q.pop_back();
                    vis[q.x][q.y]=0;
                }
                Q.push_back(now);d=0;
                vis[now.x][now.y]=1;
                Build(now);
            }
            int siz=Q.size();
            if(d+k<siz) d+=k,k=0;
            if(d+k>=hug&&k) k-=hug-d,d=hug;
            if(k)
                d=hug+(d-hug+1+k)%(siz-hug)-1;
            now=Q[d];
            printf("%d %d\n",now.x,now.y);
            f=0;
        }
    }
}

【NOIP提高組A】優美序列

題目描述

在這裏插入圖片描述
Input

在這裏插入圖片描述
Output
在這裏插入圖片描述

Sample Input

Sample Input1
7
3 1 7 5 6 4 2
3
3 6
7 7
1 3

Sample Input2
10
2 1 4 3 5 6 7 10 8 9
5
2 3
3 7
4 7
4 8
7 8

Sample Output

Sample Output1
3 6
7 7
1 7

Sample Output2
1 4
3 7
3 7
3 10
7 10

Data Constraint

在這裏插入圖片描述

題解

大概來說,據說,可能可以這樣說,這個方法可有卡過(有人寫出了985ms)。
就是對原數列我們維護一個它的映射,既對a[i]=ja[i]=jid[j]=iid[j]=i
所以對aa中一段區間[L,R][L,R]來說,找到他的Max,MinMax,Min,再找到它在idid上的值,假如對應了L,RL&#x27;,R&#x27;
所以idid[L,R][L&#x27;,R&#x27;]中的都要取,我們找到其中位置最大的和最小的,就是重新把值對應回位置,這樣就得到了一個新的aa中的區間[L,R][L,R]&#x27;,不斷重複這個操作直到找到一個合法區間就行了。
簡單說一下,合法區間就是值對應位置和位置都是值都是匹配的。
最大值最小值搞一個STST表就行了。

代碼

#pragma GCC optimize(2)
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

int read(){
    int x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=x*10+(c^48),c=getchar();
    return f?-x:x;
}
void print(int x){
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

#define MAXN 100000
int N,M;
int A[MAXN+5],pos[MAXN+5];
int Log2[MAXN+5],Pow2[MAXN+5];
int Ansl,Ansr;


#define LOG 17
int STMax0[MAXN+5][LOG+5],STMax1[MAXN+5][LOG+5];
int STMin0[MAXN+5][LOG+5],STMin1[MAXN+5][LOG+5];
void Init(){
    for(int i=1;i<=N;i++)
        Log2[i]=log2(i);
    for(int i=0;i<=LOG;i++)
        Pow2[i]=1<<i;
    for(int i=1;i<=N;i++)
        STMax0[i][0]=STMin0[i][0]=A[i],
        STMax1[i][0]=STMin1[i][0]=pos[i];
    for(int j=1;j<=LOG;j++)
        for(int i=1;i+Pow2[j-1]<=N;i++)
            STMax0[i][j]=max(STMax0[i][j-1],STMax0[i+Pow2[j-1]][j-1]),
            STMin0[i][j]=min(STMin0[i][j-1],STMin0[i+Pow2[j-1]][j-1]),
            STMax1[i][j]=max(STMax1[i][j-1],STMax1[i+Pow2[j-1]][j-1]),
            STMin1[i][j]=min(STMin1[i][j-1],STMin1[i+Pow2[j-1]][j-1]);
}
int QueryMax0(int l,int r){
    int k=Log2[r-l+1];
    return max(STMax0[l][k],STMax0[r-Pow2[k]+1][k]);
}
int QueryMax1(int l,int r){
    int k=Log2[r-l+1];
    return max(STMax1[l][k],STMax1[r-Pow2[k]+1][k]);
}
int QueryMin0(int l,int r){
    int k=Log2[r-l+1];
    return min(STMin0[l][k],STMin0[r-Pow2[k]+1][k]);
}
int QueryMin1(int l,int r){
    int k=Log2[r-l+1];
    return min(STMin1[l][k],STMin1[r-Pow2[k]+1][k]);
}

void Solve(int l,int r){
    int Max=QueryMax0(l,r),Min=QueryMin0(l,r);
    int L=QueryMin1(Min,Max),R=QueryMax1(Min,Max);
    Max=QueryMax0(L,R),Min=QueryMin0(L,R);
    if(Max-Min==R-L){
        Ansl=L,Ansr=R;
        return;
    }
    Solve(L,R);
}

int main(){
    freopen("sequence.in" ,"r", stdin);
    freopen("sequence.out","w",stdout);
    N=read();
    for(int i=1;i<=N;i++)
        pos[A[i]=read()]=i;
    Init();
    M=read();
    while(M--){
        int L=read(),R=read();
        Solve(L,R);
        print(Ansl),putchar(' '),print(Ansr),putchar('\n');
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章