1. 程式人生 > >2018.02.08【GDOI2018】模擬C組

2018.02.08【GDOI2018】模擬C組

終於結束了。。。

JZOJ NO.1 【GDOI2005】積木分發

作為最水的一道題。快排需要的積木,從小到大模擬,給不了NO,否則就YES。

#pragma GCC optimize(2)
#include <cstdio>
#include <algorithm>
#include <cctype>
using namespace std;
struct b{int x,y;}a[10002]; int n; unsigned long long s;
bool cmp(b u,b v){return u.y<v.y;}
unsigned long
long in(){ char c=getchar(); unsigned long long ans=0; while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=ans*10+c-48,c=getchar(); return ans; } bool check(int s){ for (int i=1;i<=n;i++){ if (s<a[i].y) return false;//不能幫助 s+=a[i].x;//收回積木 } return true; } int
main(){ while (n=in(),s=in(),n||s){//記住或者(二十分!) for (int i=1;i<=n;i++) a[i].x=in(),a[i].y=in(); stable_sort(a+1,a+1+n,cmp); if (check(s)) puts("YES"); else puts("NO"); } return 0; }

JZOJ NO.2 【GDOI2005】電路穩定性

純模擬,並聯電路x×y ,串聯電路x+(1-x)×y

網際網路好像無所不能,我們在網上搜集學習資料,查詢相關資訊……

進入正題。

#include <cstdio>
#include <cstring>
#include <cctype> 
using namespace std;
double a[101],p[27]; char s[101]; int n;
int news(){int m=0; for (int i=1;i<=n;i++) if (a[i]) a[++m]=a[i]; a[m+1]=0; return m;}//把0都去掉
int main(){
    scanf("%d\n",&n);
    scanf("%s",s+1); 
    for (int i=1;i<=n;i++) scanf("%lf",&p[i]); n=strlen(s+1);
    for (int i=1;i<=strlen(s+1);i++){
        if (s[i]=='(') a[i]=-1;//(變成-1
        if (s[i]==')') a[i]=-2;//以此類推
        if (s[i]==',') a[i]=-3;
     if (isupper(s[i]))a[i]=p[s[i]-64];//大寫字母變成它對應的權值
    } 
    while (n>1){
        for (int i=1;i<=n;i++){
            int j=i;
            while (a[j]>0&&a[j-1]!=-3&&a[j+1]==-3&&a[j+2]>0){//串聯
                a[j+2]=a[j]+(1-a[j])*a[j+2];//串聯公式
                a[j+1]=a[j]=0,j+=2;//變成0
            }
        }
        n=news();//清掃運算過程
        for (int i=2;i<=n;i++){
            int j=i;
            while (a[j-1]==-1&&a[j+1]==-2&&a[j+2]==-1&&a[j+4]==-2){//並聯
                a[j+3]*=a[j];//並聯公式
                a[j-1]=a[j+1]=a[j]=0,j+=3;
            }
            if (a[j-1]==-1&&a[j+1]==-2&&(a[j+2]==-3||a[j+2]==-2||!a[j+2])) a[j-1]=a[j+1]=0;//刪掉括號
        }
        n=news();//清掃運算過程
    }
    printf("%.4lf",a[1]);//剩下一個就是答案
    return 0;
}

JZOJ NO.3 【GDOI2005】飛越原野

廣搜,飛行和行走

用一個迴圈佇列儲存座標、能量、答案。

布林陣列儲存是否走過,三維,下標為座標和能量。

#pragma GCC optimize(3)
#include <cstdio>
using namespace std;
bool v[101][101][101]; char map[101][101];
const int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
struct node{
    int x,y,ans,eneg;
}q[320001];
void bfs(int n,int m,int d){
    int head=0,tail=0;
    node f1,f2;
    f1.x=f1.y=1,f1.ans=0,f1.eneg=d;//一開始初值能量滿,座標起點
    q[++tail]=f1;
    while (head!=tail){
        f1=q[++head];//出隊
        head=(head-1)%(32*n*m)+1;
        if (f1.x==n&&f1.y==m) {printf("%d",f1.ans);return;}//到達終點
        for (int i=0;i<4;i++){//走路
            f2.x=f1.x+dx[i]; f2.y=f1.y+dy[i];
            if (f2.x>0&&f2.x<=n&&f2.y>0&&f2.y<=m&&!v[f2.x][f2.y][f1.eneg]&&map[f1.x][f1.y]=='P'){//可以著陸
                f2.ans=f1.ans+1;//步數+1
                f2.eneg=f1.eneg;//能量不變
                v[f2.x][f2.y][f2.eneg]=1;//標記
                q[++tail]=f2;//入隊
                tail=(tail-1)%(32*n*m)+1;
            }
        }
        for (int j=2;j<=f1.eneg;j++){//飛行距離
            for (int i=0;i<4;i++){
                f2.x=f1.x+dx[i]*j;
                f2.y=f1.y+dy[i]*j;
                if (f2.x>0&&f2.x<=n&&f2.y>0&&f2.y<=m&&!v[f2.x][f2.y][f1.eneg-j]&&map[f1.x][f1.y]=='P'){//可以著陸
                f2.ans=f1.ans+1;//步數+1
                f2.eneg=f1.eneg-j;//減去消耗的能量
                v[f2.x][f2.y][f2.eneg]=1;
                q[++tail]=f2;//入隊
                tail=(tail-1)%(32*n*m)+1;
                }
            }
        }
    }
    puts("impossible"); return;//不可能到達
}
int main(){
    int n,m,d;
    scanf("%d%d%d\n",&n,&m,&d);
    for (int i=1;i<=n;i++) gets(map[i]+1);
    bfs(n,m,d); return 0;
}

JZOJ NO.4 【GDOI2005】電子眼

一開始看錯題目,輸出n-1,錯了。&_&

原來是樹形dp,如果這個路口裝,那麼與它相連的路口不用裝,如果這個路口不裝,那麼與它相連的路口都要裝。

#pragma GCC optimize(2)
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int n,f[100001][2],ls[100001],a[200001];
bool v[100001];
int in(){
    char c=getchar(); int ans=0;
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans;
}
void dp(int x){
    int s1=1,s2=0;
    for (int i=ls[x-1];i<=ls[x]-1;i++){
        if (!v[a[i]]){
            v[a[i]]=1;//來過。
            dp(a[i]);
            s1+=min(f[a[i]][0],f[a[i]][1]);//裝選擇最小的
        }
        s2+=f[a[i]][1];//不裝其它都要裝
    }
    f[x][1]=s1;
    f[x][0]=s2;
}
int main(){
    n=in(); ls[0]=1;
    for (int i=1;i<=n;i++){
        int x=in(); ls[i]=ls[i-1];
        for (int j=ls[i];j<=ls[i]+x-1;j++) a[j]=in();
        ls[i]+=x;} //ls儲存每個路口的路佔用的位置
    v[1]=1; dp(1); 
    printf("%d",min(f[1][0],f[1][1])); return 0;//裝和不裝的最大值
}