1. 程式人生 > >2017-10-7 清北刷題沖刺班p.m

2017-10-7 清北刷題沖刺班p.m

-s 都沒有 iostream 路線 分數 dfs img 多次 單向

測試


A 同花順


文件名 輸入文件 輸出文件 時間限制 空間限制
card.cpp/c/pas card.in card.out 1s 512MB
題目描述
所謂同花順,就是指一些撲克牌,它們花色相同,並且數字連續。
現在我手裏有 n 張撲克牌,但它們可能並不能湊成同花順。我現在想知道,最
少更換其中的多少張牌,我能讓這 n 張牌湊成一個同花順?
輸入格式
第一行一個整數 n,表示撲克牌的張數。
接下來 n 行,每行兩個整數 a i 和 b i 。其中 a i 表示第 i 張牌的花色,b i 表示第
i 張牌的數字。
(註意: 這裏的牌上的數字不像真實的撲克牌一樣是 1 到 13, 具體見數據範圍)
輸出格式
一行一個整數,表示最少更換多少張牌可以達到目標。

樣例輸入 1
5
1 1
1 2
1 3
1 4
1 5
樣例輸出 1
0
樣例輸入 2
5
1 9
1 10
2 11
2 12
2 13
樣例輸出 2
2
數據範圍
對於 30% 的數據,n ≤ 10。
對於 60% 的數據,n ≤ 10 5 ,1 ≤ a i ≤ 10 5 ,1 ≤ b i ≤ n。
對於 100% 的數據,n ≤ 10 5 ,1 ≤ a i ,b i ≤ 10 9 。

技術分享
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int
n,ans,cnt; struct node{ int col,num; }a[100010],q[100010]; int cmp(node x,node y){ if(x.col==y.col)return x.num<y.num; return x.col<y.col; } int main(){ freopen("card.in","r",stdin);freopen("card.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%d
",&a[i].col,&a[i].num); sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++){ if(a[i].col==a[i-1].col&&a[i].num==a[i-1].num)continue; q[++cnt]=a[i]; } for(int i=1;i<=cnt;i++){ int tmp=0; for(int j=i;j>=1;j--){ if(q[j].col==q[i].col&&q[i].num-q[j].num+1<=n)tmp++; else break; } ans=max(ans,tmp); } printf("%d",n-ans); fclose(stdin);fclose(stdout); return 0; }
100分


B 做實驗


文件名 輸入文件 輸出文件 時間限制 空間限制
test.pas/c/cpp test.in test.out 1s 128MB
題目描述
有一天,你實驗室的老板給你布置的這樣一個實驗。
首先他拿出了兩個長度為 n 的數列 a 和 b,其中每個 a i 以二進制表示一個集
合。例如數字 5 = (101) 2 表示集合 {1,3}。第 i 次實驗會準備一個小盒子,裏面裝
著集合 a i 所有非空子集的紙條。老板要求你從中摸出一張紙條,如果滿足你摸出的
紙條是 a i 的子集而不是 a i−b i ,a i−b i +1 ,...,a i−1 任意一個的子集,那麽你就要 ***;
反之,你就逃過一劫。
令你和老板都沒有想到的是,你竟然每次都逃過一劫。在慶幸之余,為了知道
這件事發生的概率,你想要算出每次實驗有多少紙條能使你 ***
輸入格式
第一行一個數字 n。
接下來 n 行,每行兩個整數,分別表示 a i 和 b i 。
輸出格式
n 行,每行一個數字,表示第 i 次實驗能使你 *** 的紙條數。
樣例輸入 1
3
7 0
15 1
3 1
樣例輸出 1
7
8
0
數據範圍
對於 30% 的數據,n,a i ,b i ≤ 100
對於 70% 的數據,n,a i ,b i ≤ 60000
對於 100% 的數據,n,a i ,b i ≤ 10 5
保證所有的 a i 不重復,b i < i

技術分享
#include<iostream>
#include<cstdio>
#define maxn 100010
using namespace std;
int n,a[maxn],b[maxn],l[maxn],sum[maxn][32],s[maxn][32],have[maxn][32];
int bin[1000],len;
void make(int num,int x){
    len=0;
    while(x){
        bin[++len]=x&1;
        x>>=1;
    }
    for(int i=len;i>=1;i--){
        if(bin[i]){
            sum[num][i]++;
            have[num][++have[num][0]]=i;
        }
    }
    l[num]=len;
}
int Pow(int x,int y){
    int res=1;
    while(y){
        if(y&1)res=res*x;
        x=x*x;
        y>>=1;
    }
    return res;
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("test.in","r",stdin);freopen("test.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);
    for(int i=1;i<=n;i++)//枚舉每次實驗 
        make(i,a[i]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=31;j++)
            s[i][j]=s[i-1][j]+sum[i][j];
    }
    for(int i=1;i<=n;i++){
        long long ans=0;
        int k=0;
        int now=Pow(2,have[i][0]-1);
        for(int j=1;j<=have[i][0];j++){//循環集合中的每個數 
            if(s[i-1][have[i][j]]-s[i-b[i]-1][have[i][j]]==0){
                ans+=Pow(2,have[i][0]-k-1);k++;
            }
        }
        printf("%I64d\n",ans);
    }
    fclose(stdin);fclose(stdout);
    return 0;
}
0分 暴力


C 拯救世界


文件名 輸入文件 輸出文件 時間限制 空間限制
save.cpp/c/pas save.in save.out 1s 512MB
題目描述
C 城所有的道路都是單向的。不同道路之間有路口,每個路口都有一個大樓。
有一天, 城市裏的所有大樓因為不明原因, 突然著火了。 作為超人的你要去拯救
這些大樓。初始的時候你在 S 號樓,最後你必須到達某個有補給站的大樓,你可以
沿著單向道路行駛。你可以經過某條道路或者某個大樓若幹次,經過一個大樓你就
可以消滅一個大樓的大火。每個大樓都有一個重要程度,最後這個任務的評價分數
就是你經過的所有大樓的重要度之和(若重復經過某個大樓多次,則不重復算分) 。
你是一個聰明的超人,你想知道,通過合理的規劃路線,你這次任務能得到的
最高得分是多少。
註意,該城市的道路可能有重邊或自環。
輸入格式
第一行包括兩個整數 n,m,n 表示路口的個數(即大樓的個數) ,m 表示道路
的條數。
接下來 m 行,每行兩個整數 x,y,表示 x 到 y 之間有一條單向道路。
接下來 n 行,每行一個整數,按順序表示每個大樓的重要度。
接下來一行包含兩個整數 S 和 P,S 是出發的路口(大樓)的編號,P 是有補
給站的大樓的數量。
接下來一行 P 個整數,表示有補給站的大樓的編號。
輸出格式
輸出一行一個整數,表示你得分的最大值。
樣例輸入 1
6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1
5
1 4
4 3 5 6
樣例輸出 1
47
數據範圍
對於 1、2、3 測試點,N,M ≤ 300
對於 4、5、6、7、8、9、10 測試點,N,M ≤ 3000
對於 11、12、13、14、15 測試點,N,M ≤ 500000。每個大樓的重要度均為非
負數且不超過 4000。
輸入數據保證你可以從起點沿著單向道路到達其中的至少一個有補給站的大
樓。
註意,輸入數據中存在樹和鏈的特殊情況

技術分享
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 500000
using namespace std;
int n,m,num,head[maxn],head1[maxn],w[maxn],t[maxn],s,num1,w1[maxn];
int ans=0;
struct node{
    int to,pre;
}e[maxn],e1[maxn];
void Insert(int from,int to){
    e[++num].to=to;
    e[num].pre=head[from];
    head[from]=num;
}
int dfn[maxn],low[maxn],st[maxn],belong[maxn];
bool in_st[maxn];
int s_num,cnt,group_num;
void group(int u){
    cnt++;st[++s_num]=u;dfn[u]=low[u]=cnt;in_st[u]=1;
    for(int i=head[u];i;i=e[i].pre){
        int v=e[i].to;
        if(!dfn[v]){
            group(v);
            if(low[v]<low[u])low[u]=low[v];
        }
        else if(dfn[v]<low[u])
            if(in_st[v])
            low[u]=dfn[v];
    }
    if(dfn[u]==low[u]){
        group_num++;
        while(st[s_num]!=u){
            in_st[st[s_num]]=0;
            belong[st[s_num]]=group_num;
            s_num--;
        }
        in_st[u]=0;s_num--;
        belong[u]=group_num;
    }
}
void Insert2(int from,int to){
    e1[++num1].to=to;
    e1[num1].pre=head1[from];
    head1[from]=num1;
}
bool ok[maxn];
void dfs(int now,int sum){
    if(ok[now])
        ans=max(ans,sum);
    for(int i=head1[now];i;i=e1[i].pre){
        int to=e1[i].to;
        dfs(to,sum+w1[to]);
    }
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("save.in","r",stdin);freopen("save.out","w",stdout);
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        Insert(x,y);
    }
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    int t_num;
    scanf("%d%d",&s,&t_num);
    for(int i=1;i<=t_num;i++)scanf("%d",&t[i]);
    for(int i=1;i<=n;i++){
        if(!dfn[i])group(i);
    }
    for(int now=1;now<=n;now++){
        w1[belong[now]]+=w[now];
        for(int i=head[now];i;i=e[i].pre){
            int to=e[i].to;
            if(belong[now]!=belong[to])Insert2(belong[now],belong[to]);
        }
    }
    for(int i=1;i<=t_num;i++){
        ok[belong[t[i]]]=1;
    }
    ans=w1[belong[s]];
    dfs(belong[s],w1[belong[s]]);
    printf("%d",ans);
    fclose(stdin);fclose(stdout);
    return 0;
}
72分 Tarjan縮點+dfs最短路

2017-10-7 清北刷題沖刺班p.m