1. 程式人生 > >洛谷 七月月賽

洛谷 七月月賽

P3817 小A的糖果

題目描述
小A有N個糖果盒,第i個盒中有a[i]顆糖果。
小A每次可以從其中一盒糖果中吃掉一顆,他想知道,要讓任意兩個相鄰的盒子中加起來都只有x顆或以下的糖果,至少得吃掉幾顆糖。
輸入輸出格式
輸入格式:
第一行輸入N和x。
第二行N個整數,為a[i]。
輸出格式:
至少要吃掉的糖果數量。
輸入輸出樣例
輸入樣例#1:
3 3
2 2 2
輸出樣例#1:
1
輸入樣例#2:
6 1
1 6 1 2 0 4
輸出樣例#2:
11
輸入樣例#3:
5 9
3 1 4 1 5
輸出樣例#3:
0
說明
樣例解釋1
吃掉第二盒中的糖果。
樣例解釋2
第二盒吃掉6顆,第四盒吃掉2顆,第六盒吃掉3顆。
30%的測試資料,2<=N<=20,0<=a[i], x<=100
70%的測試資料,2<=N<=1000,0<=a[i], x<=10^5
100%的測試資料,2<=N<=10^5,0<=a[i], x<=10^9

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAXN 100001
#define LL long long
int N,x,a[MAXN],c[MAXN];
LL sum;
int main(){
    scanf("%d%d",&N,&x);
    for(int i=1;i<=N;i++) scanf("%d",&a[i]);
    for(int i=1;i<=N;i++){
        c[i]=a[i]+a[i-1
]; c[i]-=x; } for(int i=1;i<=N;i++){ if(c[i]>0){ c[i+1]-=c[i]; sum+=c[i]; } } printf("%lld\n",sum); return 0; }

P3818 小A和uim之大逃離 II

題目背景
話說上回……還是參見 https://www.luogu.org/problem/show?pid=1373
小a和uim再次來到雨林中探險。突然一陣南風吹來,一片烏雲從南部天邊急湧過來,還伴著一道道閃電,一陣陣雷聲。剎那間,狂風大作,烏雲佈滿了天空,緊接著豆大的雨點從天空中打落下來,只見前方出現了一個牛頭馬面的怪物,低沉著聲音說:“呵呵,既然你們來到這,兩個都別活了!”。小a和他的小夥伴再次驚呆了!
題目描述
瞬間,地面上出現了一個H行W列的巨幅矩陣,矩陣的每個格子上要麼是空地‘.’或者障礙’#’。
他們起點在(1,1),要逃往(H,W)的出口。他們可以一次向上下左右移動一格,這個算一步操作。不過他們還保留著上次冒險時收集的魔液,一口氣喝掉後可以瞬移到相對自己位置的(D,R)向量;也就是說,原來的位置是(x,y),然後新的位置是(x+D,y+R),這個也算一步操作,不過他們僅能至多進行一次這種操作(當然可以不喝魔液)。
這個地方是個是非之地。所以他們希望知道最小能有幾步操作可以離開這個鬼地方。不過他們可能逃不出這個鬼地方,遇到這種情況,只能等死,別無他法。
輸入輸出格式
輸入格式:
第一行個整數,H W D R,意義在描述已經說明。
接下來H行,每行長度是W,僅有’.’或者’#’的字串。
輸出格式:
請輸出一個整數表示最小的逃出操作次數。如果他們逃不出來,就輸出-1。
輸入輸出樣例
輸入樣例#1:
3 6 2 1
…#..
..##..
..#…
輸出樣例#1:
5
輸入樣例#2:
3 7 2 1
..#..#.
.##.##.
.#..#..
輸出樣例#2:
-1
輸入樣例#3:
6 6 -2 0
.#….
.#.#..
.####.
.#..#.
.##.#.
….#.
輸出樣例#3:
21
說明
樣例解釋1
(1,1)→(1,2)→(1,3)→喝(3,4)→(3,5)→(3,6)
樣例解釋2
因為只有一瓶魔液所以他們沒辦法逃出來
樣例解釋3
D和R還可以是0或者負數。
資料範圍與約定
40%的測試資料2<=H,W<=5
70%的測試資料2<=H,W<=100
100%的測試資料2<=H,W<=1000,|D|

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
#define LL long long
#define MAXN 1005
int D,R,n,m;
int map[MAXN][MAXN];
bool vis[MAXN][MAXN][3];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
struct Node{ int x,y,step;bool flag; };
queue<Node> q;
bool Judge(int x,int y){
    if(x>0&&x<=n&&y>0&&y<=m) return true;
    else return false;
}
void BFS(){
    vis[1][1][0]=1;
    Node now;  now.x=1;now.y=1;now.step=0;now.flag=0;
    q.push(now);
    while(!q.empty()){
        Node u=q.front(); q.pop();
        for(int i=0;i<4;i++){
            int xx=u.x+dx[i],yy=u.y+dy[i];
            if(map[xx][yy]==1&&Judge(xx,yy)){
                if(vis[xx][yy][u.flag]==0){
                    vis[xx][yy][u.flag]=1;
                    Node v;
                    v.x=xx;v.y=yy;v.step=u.step+1;v.flag=u.flag;
                    q.push(v);
                    if(v.x==n&&v.y==m){
                        printf("%d\n",v.step);
                        return ;
                    }
                }
            }
        }
        if(u.flag==0){
            int xx=u.x+D,yy=u.y+R;
            if(map[xx][yy]==1&&Judge(xx,yy)){
                if(vis[xx][yy][1]==0){
                    vis[xx][yy][1]=1;
                    Node v;
                    v.x=xx;v.y=yy;v.step=u.step+1;v.flag=1;
                    if(xx==n&&yy==m){
                        printf("%d\n",v.step);
                        return ;
                    }
                    q.push(v);
                }
            }
        }
    }
    printf("-1");
}
int main(){
    scanf("%d%d%d%d",&n,&m,&D,&R);
    char c;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            cin>>c;
            if(c=='.') map[i][j]=1;
            else if(c=='#') map[i][j]=2;
        }
    BFS();
    return 0;
}

P3819 松江1843路

題目描述
淶坊路是一條長L米的道路,道路上的座標範圍從0到L,路上有N座房子,第i座房子建在座標為x[i]的地方,其中住了r[i]人。
松江1843路公交車要在這條路上建一個公交站,市政府希望讓最多的人得到方便,因此希望所有的每一個的居民,從家到車站的距離的總和最短。
公交站應該建在哪裡呢?
輸入輸出格式
輸入格式:
第一行輸入L、N。
接下來N行,每行兩個整數x[i]和r[i]。
輸出格式:
一個整數,最小的每個人從家到車站的距離的總和。
輸入輸出樣例
輸入樣例#1:
100 3
20 3
50 2
70 1
輸出樣例#1:
110
輸入樣例#2:
100 2
0 1
100 10
輸出樣例#2:
100
輸入樣例#3:
10000000000 5
3282894320 391
4394338332 929
6932893249 181
7823822843 440
9322388365 623
輸出樣例#3:
5473201404068
說明
樣例解釋1
當建在座標40的時候,所有人距離車站的距離總和為 |20?40|×3+|50?40|×2+|70?40|×1=110。
資料範圍和約定
對於10%的資料,1≤N≤50,R[i]=1。
對於30%的資料,1≤N≤100,R[i]≤10,1≤L≤1000。
對於70%的資料,1≤N≤1000,R[i]≤100,1≤L≤10^6。
對於全部資料,1≤L≤10^10,1≤N≤10^5,0≤x[i]≤L,1≤r[i]≤1000

//平生頭一次寫三分
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#define LL long long 
using namespace std;
const LL INF=9223372036854775807;
const double res=10;
struct node{LL x,r;}house[100005];
LL lenth,n;
LL distan(LL x){
    LL sum=0;
    for(int i=1;i<=n;i++)
        sum+=(abs(x-house[i].x)*house[i].r);
    return sum;
}
int main(){
    LL l=INF,r=-INF-1,ans=INF;
    scanf("%lld%lld",&lenth,&n);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&house[i].x,&house[i].r);
        l=min(l,house[i].x);
        r=max(r,house[i].x);
    }
    l=min(l,(LL)0);
    r=max(r,lenth);
    LL ll,rl,lm,rm;
    while(r-l>res){
        lm=l+(r-l)/3,rm=r-(r-l)/3;//三分
        ll=distan(lm),rl=distan(rm);
        if(ll>=rl) l=lm;
        else r=rm;
    }  
    for(LL i=max(l-10,(LL)0);i<=min(r+10,lenth);i++)
        ans=min(ans,distan(i));
    printf("%lld",ans);
    return 0;
}

P3820 小D的地下溫泉

題目背景
小D最喜歡泡溫泉了。小D找某奸商租下了一塊行列的地,左上角為,右下角為。小D本以為這塊地裡全是溫泉,結果這塊地極不穩定,曾經發生過一些地形變動,所以其中一些地方全是土。
題目描述
一開始他會告訴你當前這塊地的情況,但是小D有一些假操作,希望你操作給他看:
由小D指定個位置,他希望知道其中哪個位置下水泡溫泉的範圍最大。泡溫泉的範圍定義為指定位置通過向上下左右四個方向能到達的位置的個數。若詢問的位置為土,則範圍為0。如果如果有多個位置均為最大,輸出給出順序較前的那個。位置編號為。
由小D指定個位置,他會使用膜法按順序翻轉這個地方的地形。即若原位置是土,則該位置變為溫泉;若原位置是溫泉,則該位置變為土。因為小D不希望活動範圍減少得太快,所以他在將溫泉變為土時不會將一個區域分割。
輸入輸出格式
輸入格式:
第一行輸入兩個整數,,為土地大小。
接下來的行每行輸入個字元,為’.’(代表溫泉)或’*’(代表土)(不包括引號)
第行輸入一個整數,,為運算元量。
接下來的行,每行先讀入兩個整數和,表示操作型別和指定點的數量,在同一行還有個數,分別表示個操作的位置為。
輸出格式:
對於每個操作1,輸出詢問的答案並換行
輸入輸出樣例
輸入樣例#1:
5 5
.*…
.**
*….

…..
3
1 2 1 1 1 3
2 1 3 1
1 2 1 1 1 3
輸出樣例#1:
2
1
說明
對於30%的資料,
對於70%的資料,
對於100%的資料,
資料在windows下製作

//二維平面 通過標號 展成 一維座標
//scanf T一個點 
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
const int MAXN = 1001000;
int n,m,Q,d,a[MAXN],f[MAXN],s[MAXN];
int T,w,ans,sum,xx,yy,fa[MAXN],ff;
bool flag[MAXN];
int Find(int x){
    if(x==fa[x]) return x;
    else return fa[x]=Find(fa[x]);
}
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){ if(c=='-')f=-1;c=getchar(); }
    while(c>='0'&&c<='9'){ x=(x<<1)+(x<<3)+(c-'0');c=getchar(); }
    return x*f;
}
void DFS(int x,int y){
    int id=(x-1)*m+y;
    if(flag[id]||a[id]==0) return;
    flag[id]=1;f[id]=d;s[d]++;
    if(x>1) DFS(x-1,y);
    if(y>1) DFS(x,y-1);
    if(x<n) DFS(x+1,y);
    if(y<m) DFS(x,y+1);
}
void Megre(int x,int y,int x2,int y2){
    int d1=(x-1)*m+y,d2=(x2-1)*m+y2;
    int f1=Find(f[d1]),f2=Find(f[d2]);
    if(a[d1]==0||a[d2]==0||f1==f2) return;
    s[f1]+=s[f2];s[f2]=0;fa[f2]=f1;
}
int main(){
    //scanf("%d%d",&n,&m);
    n=read();m=read();
    char ch;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            ch=getchar();
            while(ch!='.'&&ch!='*') ch=getchar();
            if(ch=='.') a[(i-1)*m+j]=1;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(a[(i-1)*m+j]==1&&!flag[(i-1)*m+j]){
                d++;
                DFS(i,j);
            }
        }
    for(int i=1;i<=d;i++) fa[i]=i;
//  scanf("%d",&Q);
    Q=read();
    while(Q--){
        T=read();w=read();
        //scanf("%d%d",&T,&w);
        if(T==1){
            ans=1;sum=0;
            for(int i=1;i<=w;i++){
                xx=read();yy=read();
                //scanf("%d%d",&xx,&yy);
                ff=Find(f[(xx-1)*m+yy]);
                if(a[(xx-1)*m+yy]==0) continue;
                if(s[ff]>sum) sum=s[ff],ans=i;
            }
            printf("%d\n",ans);
        }
        else{//翻轉
            while(w--){
                xx=read();yy=read();
//              scanf("%d%d",&xx,&yy);
                if(a[(xx-1)*m+yy]==1){
                    a[(xx-1)*m+yy]=0;
                    ff=Find(f[(xx-1)*m+yy]);
                    s[ff]--;
                    f[(xx-1)*m+yy]=0;
                } else{
                    a[(xx-1)*m+yy]=1;d++;
                    f[(xx-1)*m+yy]=d;fa[d]=d;
                    s[d]++;
                    if(xx>1) Megre(xx,yy,xx-1,yy);
                    if(yy>1) Megre(xx,yy,xx,yy-1);
                    if(xx<n) Megre(xx,yy,xx+1,yy);
                    if(yy<m) Megre(xx,yy,xx,yy+1);
                }
            }
        }
    }
    return 0;
}
/*題解思路:
先用dfs/bfs搜連通塊,並且標號,
然後修改,分兩種情況,土變成溫泉,要和周圍的連通塊合併
溫泉變成土,面積直接減
然後查詢,直接一個一個掃就行。
*/