1. 程式人生 > 實用技巧 >7.1集訓模擬賽5(......)

7.1集訓模擬賽5(......)

A. 最大公約數和最小公倍數問題:

題目描述:

輸入二個正整數x0,y0(2<=x0<100000,2<=y0<=1000000),求出滿足下列條件的P,Q的個數

條件:

  1. P,Q是正整數
  2. 要求P,Q以x0為最大公約數,以y0為最小公倍數.

試求:滿足條件的所有可能的兩個正整數的個數.

輸入格式:

一行,二個正整數x0,y0。

輸出格式:

一行,即滿足條件的所有可能的兩個正整數的個數。保證答案不需要高精度。

樣例

樣例輸入:

3 60

樣例輸出:

 4

B. 方格取數:

題目描述:

設有N*N的方格圖(N<=20,我們將其中的某些方格中填入正整數,而其他的方格中則放入數字0。如下圖所示(見樣例):

某人從圖的左上角的A(1,1) 點出發,可以向下行走,也可以向右走,直到到達右下角的B(n,n)點。在走過的路上(包括起點在內),他可以取走方格中的數(取走後的方格中將變為數字0)。此人從A點到B 點共走兩次,試找出2條這樣的路徑,使得取得的數之和為最大。

輸入格式:

輸入的第一行為一個整數N(表示N*N的方格圖)

接下來的每行有三個整數,前兩個表示位置,第三個數為該位置上所放的數。一行單獨的0表示輸入結束。

輸出格式:

只需輸出一個整數,表示2條路徑上取得的最大的和。

樣例:

樣例輸入:

8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2
14 0 0 0

樣例輸出:

67
#include<bits/stdc++.h>
using namespace std;
const int N=25;
int f[N][N][N][N],a[N][N];
int n,x,y,w;
int main(){
    scanf("%d",&n);
    while(scanf("%d%d%d",&x,&y,&w)){
        if(x==0)break;
        a[x][y]=w;
    }
    f[1][1][1][1]=a[1][1];
    for(int i=1
;i<=n;i++){ for(int j=1;j<=n;j++){//i,j表示第一個人或第一條路徑走到i,j的最大分數 for(int k=1;k<=n;k++){ for(int l=1;l<=n;l++){//同i,j if(i==k&&j==l){ f[i][j][k][l]=max(max(f[i-1][j][k-1][l],f[i][j-1][k-1][l]),max(f[i][j-1][k][l-1],f[i-1][j][k][l-1]))+a[k][l]; } else { f[i][j][k][l]=max(max(f[i-1][j][k-1][l],f[i][j-1][k-1][l]),max(f[i][j-1][k][l-1],f[i-1][j][k][l-1]))+a[i][j]+a[k][l]; } } } } } printf("%d",f[n][n][n][n]); return 0; }

C. WYT的刷子:

題目描述:

WYT有一把巨大的刷子,刷子的寬度為M米,現在WYT要使用這把大刷子去粉刷有N列的柵欄(每列寬度都為1米;每列的高度單位也為米,由輸入資料給出)。

使用刷子的規則是:

  1. 與地面垂直,從柵欄的底部向上刷
  2. 每次刷的寬度為M米(當剩餘柵欄寬度不夠M米的話,刷子也可以使用,具體看樣例2)
  3. 對於連續的M列柵欄,刷子從底向上,刷到的高度只能到這M列柵欄的最低高度。

WYT請你回答兩個問題:

  1. 最少有多少個單位面積不能刷到(單位面積為1平米)
  2. 在滿足第一問的條件下,最少刷幾次?

輸入格式:

共兩行:

第一行兩個整數N和M。

第二行共N個整數,表示N列柵欄的高度。

輸出格式:

一行,兩個整數,分別為最少剩餘的單位面積數量和最少刷的次數。

樣例

樣例輸入1:

5 3
5 3 4 4 5

樣例輸出1:

3
2

樣例輸入2:

10 3
3 3 3 3 3 3 3 3 3 3

樣例輸出2:

0
4

樣例輸入3:

7 4
1 2 3 4 3 2 1

樣例輸出3:

4
4

樣例1的解釋:

高度分別為 5 3 4 4 5 如上:

黃色的方塊表示共有3個單位面積沒刷上

綠色的框和紅色的框表示一共刷了兩次。

資料範圍與提示:

30%的資料:N<=10^3

50%的資料:N<=10^5

100%的資料:1<=N<=10^6, 1<=M<=10^6,N>=M, 每列柵欄的高度<=10^6.

分析:

這到題需要用一個單調佇列維護向左向右同高度能延伸的寬度。將向左向右的相加減一就是這一高度(所在平面)的寬度。

我們用maxh陣列記錄座標為i可以刷的做大高度。

因為要求最少剩下的方塊數量,下一步我們就可以求一下每個柵欄還剩多少不能刷,遞推處理一下每個柵欄能被刷的最大高度。
我們先從左往右考慮一下,如果第i個柵欄能被刷完,那麼最大高度就是它本身的高度;如果不能,則它的高度一定比它左邊的柵欄能刷的最大高度要大(如果不成立,那麼它完全可以接在它左邊的柵欄上,把自己刷完),因此它能刷到的最大高度就是它左邊的柵欄能刷到的最大高度。
然後還要從右邊處理一下,有可能對於每一個柵欄,右邊過來可能刷的更高,所以需要求一下最值。
既然有了每個柵欄能刷的最大高度,那麼用每個柵欄的高度之和減去所有能刷的最大高度就是剩餘的面積。

從左向右,從右向左更新maxh的值,同時記錄最少沒有刷的,最終輸出。

小結:

這道題我是又找教練員認認真真又聽了一邊,對於單調佇列得維護可以模擬一下(模擬了之後非常理解),記錄延伸寬度也是模擬了,也非常理解。

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;
ll n,m;
ll a[N];
ll q[N];
ll j[N];
ll maxh[N],l[N],r[N];
ll sum;
int main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        sum+=a[i];//記錄總面積
    }
    int head=0,tail=-1;
    for(int i=1;i<=n+1;i++){
        while(head<=tail&&a[i]<a[q[tail]]){
            r[q[tail]]=i-q[tail];//單調佇列維護求向右延伸的寬度
            tail--;
        }
        q[++tail]=i;
    }
    head=0;tail=-1;
    for(int i=n;i>=0;i--){
        while(head<=tail&&a[i]<a[q[tail]]){
            l[q[tail]]=q[tail]-i;//維護向左延伸的寬度
            tail--;
        }
        q[++tail]=i;
    }
    for(int i=1;i<=n;i++){
        if(l[i]+r[i]-1>=m)j[i]=1;//j是一個記錄陣列,作用是記錄第i個柱子能否被刷完,用bool型別的也可以
    }//這就用到l陣列和r陣列了注意減一
    for(int i=1;i<=n;i++){//從左向右
        if(j[i]==1){
            maxh[i]=a[i];//如果i刷不完,它一定得與i-1能刷的最大高度
        } else {
            maxh[i]=maxh[i-1];
        }
    }
    for(int i=n;i>=1;i--){//從右向左
        if(!j[i]){//如果i刷不完
            maxh[i]=max(maxh[i],maxh[i+1]);//那麼i能刷的最大高度為i和i+1的最大高度
        }
        sum-=maxh[i];
    }
    ll k=2,ans=0;
    while(k<=n+1){//找同一高度的寬度
        int cnt=1;
        while(k<=n+1&&maxh[k]==maxh[k-1]){
            cnt++;
            k++;
        }
        ans+=cnt/m;
        if(cnt%m!=0)ans++;//如果寬度不能整除,肯定還要在加一次
        k++;
    }
    printf("%lld\n%lld",sum,ans);
    return 0;
}

D. 2017種樹:

題目描述:

2017共有N棵樹從0到N-1標號。現要把這些樹種在一條直線上,第i棵樹的種植位置X[i]如下確定:

X[0] = X[0] MOD L;

X[i] = (X[i-1]*A+B) MOD L。

每棵樹種植的費用,是所有標號比它小的樹與它的距離之和。2017請你計算各棵樹的費用之積,最後對1000000007取餘。

輸入格式:

共五行:

第一行為N

第二行為L

第三行為X[0]

第四行為A

第五行為B

輸出格式:

總費用

樣例:

樣例輸入:

5
10
3
1
1

樣例輸出:

180

樣例解釋:

5棵樹的位置分別為: 3, 4, 5, 6, 7.

費用分別為: 1, 3, 6, 10. (從第一棵樹開始)

總費用為: 1 × 3 × 6 × 10 = 180.

資料範圍與提示:

10%的資料:N<=10;

60%的資料:N<=2×10^5;

100%的資料:N,L<=200000; X[0] ,A, B<=10^9.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
ll n,l,x,a,b;
ll c1,c2,s1,s2;
ll cost,ans = 1;
struct edge{
    ll cnt;
    ll val;
}tree[N<<2];



void updata(int rt,int l,int r,int x,int val){
    if (l > x || r < x) return;
    if(l==r){
        tree[rt].val+=val;
        tree[rt].cnt++;
        return ;
    }
    ll mid = (l+r)>>1;
    if(x<=mid){
        updata(rt*2,l,mid,x,val);
    } else {
        updata(rt*2+1,mid+1,r,x,val);
    }
    tree[rt].cnt=tree[rt*2].cnt+tree[rt*2+1].cnt;
    tree[rt].val=tree[rt*2].val+tree[rt*2+1].val;
    //return ;
}

ll getval(int rt,int l,int r,int x,int y){
    if(y<l||x>r)return 0;
    if(x<=l&&y>=r)return tree[rt].val;
    ll mid = (l+r)>>1;
    ll sum=0;
    if(x<=mid){
        sum+=getval(rt*2,l,mid,x,y);
    }if(y>mid){
        sum+=getval(rt*2+1,mid+1,r,x,y);
    }
    return sum;
}

ll getcnt(int rt,int l,int r,int x,int y){
    if(y<l||x>r)return 0;
    if(x<=l&&y>=r)return tree[rt].cnt;
    ll mid = (l+r)>>1;
    ll sum=0;
    if(x<=mid){
        sum+=getcnt(rt*2,l,mid,x,y);
    }if(y>mid){
        sum+=getcnt(rt*2+1,mid+1,r,x,y);
    }
    return sum;
}


int main(){
    scanf("%lld%lld%lld%lld%lld",&n,&l,&x,&a,&b);
    x=x%l;
    //updata(1,1,l,x+1,x);
    for(int i=1;i<n;i++){
        updata(1,1,l,x+1,x+1);
        x=(x*a+b)%l;
        c1=getcnt(1,1,l,1,x+1);
        c2=i-c1;
        s1=getval(1,1,l,1,x+1);
        s2=tree[1].val-s1;
        cost = (c1*(x+1)-s1+s2-c2*(x+1))%1000000007;
        //printf("%lld  %lld  %lld  %lld\n",c1,c2,s1,s2);
        //printf("%lld\n",cost);
        ans = (ans*cost)%1000000007;
        //updata(1,1,l,x+1,x);
    }
    printf("%lld",ans);
    return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
typedef long long ll;
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define MAXTREE 200001

const int N = 200000 + 10;
const int MOD = 1000000007;

struct SegTree {
    ll sum;
    int cnt;
} tree[N << 2];

int n, L, a, b;
int x;
ll ans = 1;
int tot;

void pushup(int rt) {
tree[rt].sum = (tree[lson].sum + tree[rson].sum);
tree[rt].cnt = tree[lson].cnt + tree[rson].cnt;
}

void update(int rt, int L, int R, int pos, int val) {
    if (L > pos || R < pos) return;
    if (L == R) {
        tree[rt].sum = (tree[rt].sum + val);
        ++tree[rt].cnt;
        return;
    }
    int mid = (L + R) >> 1;
    if (mid < pos) update(rson, mid+1, R, pos, val);
    else update(lson, L, mid, pos, val);
    pushup(rt);
}

int qeurycnt(int rt, int L, int R, int l, int r) {
    if (L > r || R < l) return 0;
    if (l <= L && r >= R) return tree[rt].cnt;
    int mid = (L + R) >> 1;
    return qeurycnt(lson, L, mid, l, r) + qeurycnt(rson, mid + 1, R, l, r);
}

ll qeurysum(int rt, int L, int R, int l, int r) {
    if (L > r || R < l) return 0;
    if (l <= L && r >= R) return tree[rt].sum;
    int mid = (L + R) >> 1;
    return (qeurysum(lson, L, mid, l, r) + qeurysum(rson, mid + 1, R, l, r));
}

int main() {
    scanf("%d%d%d%d%d", &n, &L, &x, &a, &b);
    x = x % L;
    int c1, c2;
    ll s1, s2, sum = 0;
    for (int i = 1; i < n; ++i) {
    update(1, 1, L, x+1, x+1); // 從 1 開始
    //sum = (sum + x + 1) % MOD;
    x = ((ll)x * a % L + b) % L;
    //printf("x = %lld\n", x);

    c1 = qeurycnt(1, 1, L, 1, x+1);
    //c2 = qeurycnt(1, 1, MAXTREE, x+1, MAXTREE);
    c2 = i - c1;
    s1 = qeurysum(1, 1, L, 1, x+1);
    //s2 = qeurysum(1, 1, MAXTREE, x+1, MAXTREE);
    s2 = tree[1].sum - s1;
    printf("%d  %d  %lld  %lld\n",c1,c2,s1,s2);
    //printf("c1 = %d c2 = %d s1 = %lld s2 = %lld\n", c1, c2, s1, s2);

    ll cost = (((ll)c1 * (x+1) % MOD - s1 + s2 - (ll)c2 * (x+1) %MOD)%MOD+MOD)%MOD;
    //printf("cost = %lld\n", cost);
    ans = ans * cost % MOD;
    
    //update(1, 1, MAXTREE, x, x);
}
printf("%lld\n", ans);
return 0;
}

分析: