20190330考試

#T1重置序reset
一個芯片可以有N種不同的狀態,不妨設爲0到N-1。其中,0狀態是準備狀態。當芯片出現錯誤時,可能會處於任意狀態。因此需要一個重置序列來將它變成準備狀態。你的任務就是尋找這個重置序列。
當芯片處於狀態i時接收了命令j,它會立刻轉變成狀態d[i,j]。對於任意初始狀態,你找到的重置序列都應最終將它變成準備狀態。在此基礎上,你找到的重置序列應該最短。
##輸入
第一行兩個整數$n,m(2<=n<=8,1<=m<=16)$,表示狀態數和命令數。
接下來n行每行m個整數,表示狀態i在接收到命令j時會變成狀態d[i,j]。注意,狀態和命令都是從0開始編號的。其中,0是唯一一個準備狀態。保證$0<=d[i,j]<n$。
##輸出
輸出一個序列表示最短操作序列。用16進制數來表示操作$(0-9,a-f)$。數碼之間、行尾都不應有多餘字符。如果有多組解,輸出字典序最小的一組。如果無解,輸出-1。
樣例輸入
```
3 4
2 1 1 2
1 0 0 0
0 0 0 1
```
樣例輸出
```
101
```
提示
【樣例說明】
三種狀態都會通過這個序列最終變成狀態0:
0->1->1->0
1->0->2->0
2->0->2->0
算是狀態壓縮dp吧。。。觀察發現n的範圍非常小,我們用一個整數作爲狀態,狀態裏面每個位表示芯片狀態是否存在。然後就考慮轉移,我們枚舉轉移,又由於字典序最小,直接bfs就好了。初始狀態爲$(1<<n)-1$目標狀態$1$,因爲只剩一個0狀態了,也就是0位上爲1。
代碼:
 

#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
const int N = 10,S = 1<<16;
int q[S],op[S],fa[S],G[N][N*2],front,tail,f[S];
int n,m;
void print(int x){
    if(op[x]==-1)return;
    print(fa[x]);
    printf("%x",op[x]);
}
int bfs(int s){
    f[s] = 1;
    front = tail = 1;
    op[tail] = -1;fa[tail] = 0;
    q[tail++] = s;
    while(tail!=front){
        int t = q[front];
        if(t==1)return front;
        for(int i = 0;i<m;i++){
            int x = 0;
            for(int j = 0;j<n;j++){
                if(t&(1<<j))x|=1<<G[j][i];
            }
            if(x&&!f[x]){
                f[x] = 1;
                q[tail] = x;
                fa[tail] = front;
                op[tail] = i;
                tail++;
            }
        }
        front++;
    }
    return 0;
}
int main(){
    cin>>n>>m;
    for(int i = 0;i<n;i++)
        for(int j = 0;j<m;j++)
            cin>>G[i][j];
    int ans = bfs((1<<n)-1);
    if(ans)print(ans);else cout<<-1<<endl;
    return 0;
}

#T2
你的防線成功升級,從原來的一根線變成了一棵樹。這棵樹有 N 個炮臺,炮臺與炮臺之間 有 N-1 條隧道。你要選擇一些炮臺安裝哨戒炮。在第 i 個炮臺上安裝哨戒炮得到的防禦力爲 vi。上次說過,哨戒炮離得太近會產生神奇的效果。具體來說,對於炮臺 i,如果它安裝了 哨戒炮且和 k 個哨戒炮用隧道直接相連,那麼其防禦力會變化 k*di。其中 di 爲炮臺 i 的抗 干擾屬性值。如果爲正,干擾對其有正的作用;爲負,干擾對其有負的作用;爲 0,則完全 不受干擾。
你的整套防線的防禦力爲所有哨戒炮的防禦力之和。求防線的最大防禦力
##輸入
第一行一個整數 N,表示炮臺數量。
第二行 N 個整數表示 vi。
第三行 N 個整數表示 di。
接下來 N-1 行每行兩個整數描述一條隧道。
##輸出
輸出一行一個整數表示答案
樣例輸入
```
2
1 1
0 0
1 2
```
樣例輸出
```
2
```
提示
對於 20%的數據,$N <= 20$。
對於 40%的數據,$N <= 100$。
對於 70%的數據,$N <= 5000$。
對於 100%的數據,$N <= 100000$
最水的一道題,樹形dp,但是注意long long ,不開long Long 只有10分,見祖宗

#include <cstdio>
const int MAXN = 100010;
struct edge{int t,next;}edges[MAXN<<2];
int head[MAXN],top;
void add(int f,int t){
    edges[++top].next = head[f];
    edges[top].t = t;
    head[f] = top;
}
long long max(long long a,long long b){return a>b?a:b;}
long long dp[MAXN][2];
long long v[MAXN],d[MAXN];
void dfs(int x,int fa){
    dp[x][1] = v[x];dp[x][0] = 0;
    for(int i = head[x];i;i = edges[i].next){
        int t = edges[i].t;
        if(t==fa)continue;
        dfs(t,x);
        dp[x][1] += max(dp[t][0],d[t]+d[x]+dp[t][1]);
        dp[x][0] += max(dp[t][0],dp[t][1]);
    }
}
int main(){
    int n;scanf("%d",&n);
    for(int i = 1;i<=n;i++)scanf("%lld",&v[i]);
    for(int i = 1;i<=n;i++)scanf("%lld",&d[i]);
    int f,t;
    for(int i = 1;i<n;i++){
        scanf("%d %d",&f,&t);
        add(f,t);add(t,f);
    }
    dfs(1,0);
    printf("%lld",max(dp[1][1],dp[1][0]));
    return 0;
}


#T3里程錶
Farmer John's cows are on a road trip! The odometer on their car displays an integer mileage value, starting at X (100 <= X <= 10^18) miles at the beginning of their trip and ending at Y (X <= Y <= 10^18) miles at the end of their trip. Whenever the odometer displays an 'interesting' number (including at the start and end of the trip) the cows will moo. A number is 'interesting' if when you look at all its digits except for leading zeros, at least half of these should be the same. For example, the numbers 3223 and 110 are interesting, while the numbers 97791 and 123 are not.
Help FJ count how many times the cows will moo during the trip.
農民約翰的牛正開始一個美妙的旅程。牛車的里程錶上顯示一個整數表示里程,旅程開始時里程數爲$X(100 <= X <= 10^18)$,結束時里程數爲$Y(X <= Y <= 10^18)$。每當里程錶顯示一個有趣的數時(包括起點和終點數),牛們會發出愉快的叫聲。
對於一個里程數的每一位,如果有至少一半的數字時相同的,則這個里程數一個有趣的數。例如:3223和110是有趣的數,而$97791$ 和 $123$則不是。
請計算,整個旅程中,牛們會發出多少吃愉快的叫聲。
輸入
Line 1: The first line will contain two integers, X and Y, separated by a space.
輸出
Line 1: A single integer containing how many times the cows will moo during the trip.
樣例輸入
```
110 133
```
樣例輸出
```
14
```
提示
The trip starts with the odometer at 110 and ends at 133.
The cows moo when the odometer reads 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 131, and 133.
標籤
USACO2014 US Open, Silver
數位dp,第一次計算出1-9每個數字出現次數超過一半的數的個數,再求出2個數各佔一半的數的個數,然後一減就好了。
代碼:
 

#include <iostream>
#include <cstring>
using namespace std;
long long dp[20][20][20][20];
long long dp2[20][20][20][20];
int nm[20];
long long dfs1(int pos,int num,int cnt,int len,bool lead,bool limit){
    if(pos==0){return cnt*2>=len;}
    if(!lead&&!limit&&dp[pos][num][cnt][len]!=-1)return dp[pos][num][cnt][len];
    long long ans = 0;int mx = limit?nm[pos]:9;
    for(int i = 0;i<=mx;i++){
        ans+=dfs1(pos-1,num,cnt+(i==num&&(!lead||i!=0)),len-(lead&&i==0),i==0&&lead,limit&&i==mx);
    }
    if(!lead&&!limit)dp[pos][num][cnt][len] = ans;
    return ans;
}
long long dfs2(int pos,int num1,int num2,int cnt1,int cnt2,int len,int lead,int limit){
    if(pos==0)return cnt1*2==len&&cnt1==cnt2;
    if(!lead&&!limit&&dp2[pos][cnt1][cnt2][len]!=-1)return dp2[pos][cnt1][cnt2][len];
    long long ans = 0;int mx = limit?nm[pos]:9;
    if(lead)ans+=dfs2(pos-1,num1,num2,cnt1,cnt2,len-1,true,false);
    if(num1<=mx&&(num1!=0||!lead))ans+=dfs2(pos-1,num1,num2,cnt1+1,cnt2,len,false,limit&&num1==mx);
    if(num2<=mx&&(num2!=0||!lead))ans+=dfs2(pos-1,num1,num2,cnt1,cnt2+1,len,false,limit&&num2==mx);
    if(!lead&&!limit)dp2[pos][cnt1][cnt2][len] = ans;
    return ans;
}
long long work(long long x){
    long long ans = 0;
    int len = 0;
    while(x){
        nm[++len] = x%10;x/=10;
    }
    for(int i = 0;i<=9;i++)ans+=dfs1(len,i,0,len,true,true);
    for(int i = 0;i<=9;i++)
        for(int j = i+1;j<=9;j++)
            memset(dp2,-1,sizeof(dp2)),ans-=dfs2(len,i,j,0,0,len,true,true);
    return ans;
}
int main(){
    long long l,r;
    memset(dp,-1,sizeof(dp));
    memset(dp2,-1,sizeof(dp2));
    cin>>l>>r;
    cout<<work(r)-work(l-1);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章