模擬賽1124

A.養花

flower.cpp/in/out
Time Limit: 1s
Memory Limit: 512MB
Description
小 C 在家種了 n 盆花, 每盆花有一個豔麗度 a i .
在接下來的 m 天中, 天天早晨他會從一段編號連續的花中選擇一盆擺
放在客廳, 並在晚上放回. 同時天天有特定的光照強度 k i , 若是這一天裏擺
放在客廳的花豔麗度爲 x, 則他能得到的喜悅度爲 x mod k i .
他但願知道, 每一天他能得到的最大喜悅度是多少.
Input Format
數據第一行包含兩個正整數 n, m.
接下來一行 n 個正整數, 第 i 個數 a i 表示第 i 盆花的豔麗度.
接下來 m 行, 每行三個正整數 l i , r i , k i , 表示選花區間和光照強度.
Output Format
輸出 m 行, 每行一個整數, 表示最大喜悅度.
Sample Input
5 5
1 2 3 4 5
1 3 2
2
1 3 3
1 4 4
5 5 5
3 5 3
Sample Output
1
2
3
0
2
Constraints
對於 20% 的數據, n, m ≤ 4000.
對於 40% 的數據, n, m ≤ 50000.
對於另外 20% 的數據, a i ≤ 300.
對於 100% 的數據, n, m, a i , k i ≤ 10 5 .
--------------c++

20分作法

對於每次詢問,直接枚舉便可。複雜度O(n^2)。git

40分作法

能夠預處理出k=1~300時全部位置的答案,開個桶就好。複雜度O((n+m)*300)數組

55分作法(個人作法)

考場上想到了分塊,在每一個塊內預處理出k=1~300時的答案,對於k>300的部分,
能夠對每一個塊開一個1e5的數組f,f[i]記錄的是<i的這個塊裏出現的最大數,
這樣,對於給定的k,k-(i-f[i])就有可能成爲最優解。查詢時,對於每一個整塊,
分別令i=k,2k,3k...min(nk,100000),更新答案便可;對於非整塊,暴力就好。
複雜度最壞是O(n^2)。不過實際評測時居然沒有一個點TLE。。。spa

100分正解

只須要預處理出上述過程的答案就好,複雜度O(n*(nlogn^0.5)),利用均值不等式
易得出塊大小N=1000時複雜度最優。code

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
    re g=1;register char ch=getchar();res=0;
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
const int N=100000,E=1000;
int n,m,L,R,W,sum,X,Y,ans,l[101000],b[101000],f[110][101000],a[101000],len;
int main(){
    //freopen("flower0.in","r",stdin);
    //freopen("flower.out","w",stdout);
    read(n);read(m);len=E;n--;
    F(i,0,n){
        read(a[i]);
        b[i]=(i/len)+1;
    }
    F(i,1,b[n]){
        memset(l,0,sizeof(l));
        F(j,(i-1)*len,min(i*len,n)){
            l[a[j]]=a[j];
        }
        F(j,1,N){
            l[j]=max(l[j],l[j-1]);
        }
        F(j,1,N){
            for(re k=0;k<=N;k+=j)f[i][j]=max(f[i][j],l[min(k+j-1,N)]-k);
        }
    }
    while(m--){
        read(L);read(R);read(W);L--;R--;
        X=b[L];Y=b[R];ans=0;
        if(X+1<=Y-1){
            F(i,X+1,Y-1){
                ans=max(ans,f[i][W]);
            }
        }
            F(i,L,min(X*len,R)){
                ans=max(ans,a[i]%W);
            }
            F(i,max(L,(Y-1)*len),R){
                ans=max(ans,a[i]%W);
            }
            printf("%d\n",ans);
        
    }
    return 0;
}
/*
5 5
1 2 3 4 5
1 3 2
1 3 3
1 4 4
5 5 5
3 5 3
*/

這題的數據好像有點問題,N只要不是1000就WA。。。
原本個人假程序好像是能夠AC的。。。orm


B.折射

refract.cpp/in/out
Time Limit: 1s
Memory Limit: 128MB
Description
小 Y 十分喜好光學相關的問題, 一天他正在研究折射.
他在平面上放置了 n 個折射裝置, 但願利用這些裝置畫出美麗的折線.
折線將從某個裝置出發, 而且在通過一處裝置時能夠轉向, 若通過的裝置坐
標依次爲 (x 1 ,y 1 ),(x 2 ,y 2 ),...(x k ,y k ), 則必須知足:
• ∀j ∈ (1,k], y j < y j−1
• ∀j ∈ (2,k], x j−2 < x j < x j−1 or x j−1 < x j < x j−2
如今他但願你能告訴他, 一共有多少種不一樣的光線能被他畫出來, 兩
種光線不一樣當且僅當通過的折射裝置的集合不一樣. 你只須要告訴他答案對
10 9 + 7 取模後的結果.
Input Format
第一行一個正整數 n, 表示折射裝置的數量.
接下來 n 行, 每行兩個整數 x i ,y i 表示折射裝置的座標.
Output Format
輸出一行一個整數, 表示答案對 10 9 + 7 取模後的結果.
Sample Input
4
2 2
3 1
1 4
4 3
Sample Output
14
Constraints
對於 10% 的數據: n ≤ 700,1 ≤ x i ,y i ≤ N
對於 20% 的數據: n ≤ 1000,1 ≤ x i ,y i ≤ N
對於 50% 的數據: n ≤ 4000,|x i |,|y i | ≤ 10 9
對於 100% 的數據: n ≤ 6000,|x i |,|y i | ≤ 10 9
全部數據知足 ∀i ̸= j, x i ̸= x j and y i ̸= y j .排序


考試時只想到n^3暴力,想着能夠騙10分,結果手殘開了個f[6060][6060]沒算空間,直接MLE。。
直接說正解吧。。
首先,確定不能以y座標排序,這樣複雜度只能是n^3。
咱們把全部點按x座標升序排列。枚舉i節點,考慮在已有的折線中加入i。
考慮到i的橫座標是最大的,因此它只多是折線的第一個或第二個。
由於它是折線,咱們天然就想到用左或右來做爲一個dp轉移的狀態。
設f[i][0/1]表示i號節點爲y座標最大值時,折線接下來向左或向右的方案數。
那有哪些節點能夠轉移呢?
考慮枚舉i以前的點j。
對於y[j]<y[i]的節點,f[j][1]天然而然能夠轉移到f[i][0];
對於y[j]>y[i]的節點,i能夠向j進行轉移。
但是這樣就存在一個問題:並非全部的f[i][0]表示的折線都能合法地轉移到f[j][1]。
所以,咱們不得不枚舉k,當?y[i]>y[k]且x[k]>x[j]時才能轉移。
粗問題了!!!這不就n^3了嗎?
但當咱們再仔細研究這兩個條件時,發現:f[i][0]是全部知足y[k]<y[i]的f[k][1]之和。
那如何處理f[i][0],才能知足x[k]>x[j]呢?
發現x座標是有序的,那咱們倒序枚舉j不就好了嗎!!
很好的一道思惟題。。ip

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
I read(int &res){
    res=0;re g=1;register char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
struct P{
    int x,y;
    friend bool operator < (P a,P b){
        return a.x==b.x?a.y<b.y:a.x<b.x;
    }
}p[6060];
const int E=1e9+7;
int n,m,f[6060][2],ans;
int main(){
    freopen("refract5.in","r",stdin);
    freopen("refract.out","w",stdout);
    read(n);
    F(i,1,n){
        read(p[i].x);read(p[i].y);
    }
    sort(p+1,p+1+n);
    F(i,1,n){
        f[i][0]=f[i][1]=1;
        FOR(j,i-1,1){
            if(p[j].y>p[i].y)f[j][1]=(f[j][1]+f[i][0])%E;
            else f[i][0]=(f[i][0]+f[j][1])%E;
        }
    }
    ans=E-n;
    F(i,1,n){
        ans=(ans+f[i][0])%E;
        ans=(ans+f[i][1])%E;
    }
    printf("%d",ans);
    return 0;
}

C.畫做

paint.cpp/in/out
Time Limit: 1s
Memory Limit: 128MB
Description
小 G 的喜歡做畫, 尤爲喜歡僅使用黑白兩色做畫.
畫做能夠抽象成一個 r ×c 大小的 01 矩陣. 如今小 G 構思好了了他的
畫做, 準備動筆開始做畫. 初始時畫布是全白的, 他每一次下筆能夠將一個
四聯通的部分塗成黑色或白色.
你須要告訴他, 在給出的構思下, 他最少須要下筆多少次才能完成畫做.
Input Format
第一行兩個正整數 r, c.
接下來 r 行, 每行 c 個字符, 表示目標畫做.
Output Format
輸出一行一個正整數, 表示最少須要的下筆步數.
Sample Input
3 3
010
101
010
Sample Output
2
Constraints
• Subtask 1 (19pts): r × c ≤ 15.
• Subtask 2 (7pts): r = 1.
• Subtask 3 (25pts): r, c ≤ 30.
• Subtask 4 (49pts): r, c ≤ 50.get


不難證實猜到一個這樣的結論: 存在一種最優方案使得每次操做的區
域是上一次的子集且顏色與上一次相反.
考慮概括證實, 記 S 爲當前全部操做區域的並, T 爲接下來一步的操做
區域, 咱們有:it

  1. T 與 S 有交的狀況必定能夠轉化成 T 被 S 包含的狀況.
  2. T 與 S 交集爲空時, 能夠找一個鏈接 S 和 T 的集合 M 並操做 S ∪
    T ∪M, 並將以前的全部操做鏈接到更外的層以及外層的鏈接部分同時
    操做, 特殊處理最外層和第二層的狀況.
  3. T 被 S 包含時, T 落在某個完整區域內時等價於狀況二, 不然必定連
    接若干個同色塊, 這些塊能夠同時處理, 步數必定不會更劣.
    知道這個結論就比較好作了, 咱們能夠枚舉最後被修改的區域, 這時答
    案就是將同色邊邊權看成 0, 異色邊邊權看成 1 後距離這個點最遠的黑色點
    的距離, 對全部點取最小值便可.
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
I read(int &res){
    res=0;re g=1;register char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
const int INF=1e9+7;
char c[60][60];
int mx[5]={0,1,0,-1,0},my[5]={0,0,1,0,-1};
int n,m,X,Y,dis[60][60],ans;
typedef pair<int,int>pii;
#define mp(x,y) make_pair(x,y)
deque<pii>q;
IN B_1(int x,int y){
    re res=0;
    memset(dis,-1,sizeof(dis));
    dis[x][y]=0;
    q.push_back(mp(x,y));
    while(!q.empty()){
        x=q.front().first;y=q.front().second;q.pop_front();
        if(c[x][y]=='1')res=max(res,dis[x][y]);
        F(i,1,4){
            X=x+mx[i];Y=y+my[i];
            if(X>=1&&X<=n&&Y>=1&&Y<=m&&dis[X][Y]==-1){
                if(c[x][y]==c[X][Y]){
                    dis[X][Y]=dis[x][y];
                    q.push_front(mp(X,Y));
                }
                else{
                    dis[X][Y]=dis[x][y]+1;
                    q.push_back(mp(X,Y));
                }
            }
        }
    }
    return res;
}
int main(){
    read(n);read(m);
    F(i,1,n){
        scanf("%s",c[i]+1);
    }
    ans=INF;
    F(i,1,n){
        F(j,1,m){
            ans=min(ans,B_1(i,j));
        }
    }
    printf("%d",ans+1);
    return 0;
}

總結

本次模擬賽考了55+0+0。雖然考試時前兩題都想到了很是接近正解的思路, 但就是差那麼一點點。仍是要多多打怪作題,積攢經驗。

相關文章
相關標籤/搜索