動態規劃測試test20170513

前言

這次考試有三個人AK,而我卻因爲被第三題我原來的做法雖然能夠oj(難道是oj上的數據水?),被卡成50分,然後就250了。
然後這次考試跟平常理解的dp沒有多大的關係。

題目

1.祖先們都在看着你(ancestors.pas/c/cpp)

Time Limit:1s Memory Limit:256MB

【題目描述】

公元前 2000 年。在某塊草原中,生活着一羣牛,它們都有着自己的圖騰和信仰。因此,不同信仰的牛們很自然地分爲了各個部族。爲了自己所在部族的神靈,牛們經常會發起聖戰,爲神靈奪取地盤。在很長一段時間內,各個部族的矛盾幾乎到達了不可調和的地步!這時,在衆牛中,出現了一位豪傑,他在短時間內將各部族拉入麾下,建立起了血蹄部族。他就是後來爲牛們所傳頌的偉人:孛兒只斤•彰異牛,又名蜃牛•血蹄。他給牛們帶來了文明。教會了牛們只用兩個後蹄走路,空出前蹄來工作,以致於出現了後來謙遜而不失高貴,致力於侍奉自然的牛頭人族。而那片草原正是後來的莫高雷。(求不吐槽……)
牛頭人們的生活不是和平的,它們侍奉自然,對破壞自然平衡、褻瀆大地母親的行爲深惡痛絕,所以,它們有着自己訓練有素的軍隊。孛兒只斤•彰異牛逝世多年後,由於牛頭人們的信仰,它們一直相信祖先彰異牛在看着它們(囧),正因爲如此,它們在軍隊訓練過程中沒有絲毫懈怠。
某天,在彰異牛的注視下,N 個牛頭人(依次標號 1 到 N)加入了軍隊,由某牛頭人隊長帶領。而軍隊審查了他們的資料後,給出了 M 條指示,第 i 條指示的內容是:第 Ai 號牛頭人必須站在第 Bi 號牛頭人的左邊,指示之間不會出現矛盾。牛頭人隊長拿到指示後,便開始規劃 N 個牛頭人的列隊方式了。
現在,你需要用計算機的力量秒殺(1s 運行時間搞定)牛頭人隊長!

【輸入格式】

第一行 2 個數字 N,M。
接下來 M 行,每行兩個數字 AiBi

【輸出格式】

輸出 N 行,即 N 個牛頭人的站隊序列。如果有多個站隊序列滿足要求,輸出任意一個即可。

【樣例輸入輸出】

ancestors.in
5 4
1 2
2 3
3 4
4 5
ancestors.out
1
2
3
4
5

【樣例解釋】

1 在 2 前,2 在 3 前,3 在 4 前,4 在 5 前、只有排列 12345 滿足要求。

【數據範圍】

10%的數據 1N81M28
40%的數據 1N10001M105
100%的數據 1N1051M106

【題解】

題目太水,顯然的拓撲排序求拓撲序列。
寫法很多。

【代碼】


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

template< typename Type >inline void Read( Type &In ){
    In=0;char ch=getchar();
    for( ;ch> '9'||ch< '0';ch=getchar() );
    for( ;ch>='0'&&ch<='9';ch=getchar() )In = In*10 + ch-'0';
}

typedef long long LL;
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))

const int size = 1000000+10;
int n,m,cnt;
int du[size],head[size],val[size],nxt[size];
bool vis[size];

queue<int> q;

void add_edge(int x,int y) {
    nxt[cnt]=head[x];val[cnt]=y;head[x]=cnt++;
}

int main() {
    freopen("ancestors.in","r",stdin);
    freopen("ancestors.out","w",stdout);
    memset(head,-1,sizeof head);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) {
    int x,y;Read( x );Read( y );//scanf("%d%d",&x,&y);
    add_edge(x,y);du[y]++;
    }
    for(int i=1;i<=n;i++)
    if(!du[i])q.push(i);
    while(!q.empty()) {
    int now=q.front();q.pop();
    if(!vis[now]) {
        vis[now]=true;printf("%d\n",now);
    }
    for(int i=head[now];i!=-1;i=nxt[i]) {
        du[val[i]]--;
        if(!du[val[i]]) q.push(val[i]);
    }
    }
    return 0;
}

2.願大地母親保佑你(bless.pas/c/cpp)

Time Limit:1s Memory Limit:256MB

【題目描述】

牛頭人們的生活從來不是和平的。刺背野豬人、鷹身人等種族經常來騷擾他們,還有一個很欠抽的某巨魔及其麾下的軍隊。
某天,仍然是在彰異牛的注視下,某牛頭人臨危受命,在大地母親的保佑下,拿回了一張圖紙,圖紙上畫的是某巨魔的組織關係示意圖。這個圖中包含的是某巨魔組織的從屬關係(直屬上級和直屬下級),圖繪製出來後的形態是 N 個點的樹,但是這張圖沒有告訴牛頭人對於一對有從屬關係的巨魔,誰是上級誰是下級。巨魔中肯定有個最高指揮官(即沒有從屬上級的巨魔),但是牛頭人現在不好判斷哪個巨魔是最高指揮官了。
經過一個牛頭人大德魯伊分析後,得出結論,如果將某個巨魔從這個關係圖中去掉後,這個圖剩下的連通塊中,點數最多那個塊在所有去掉的方案中的點數最少,那麼這個巨魔可能就是最高指揮官。現在,牛頭人需要你找出一個最高指揮官。

【輸入格式】

第一行 1 個數字 N。
接下來 N-1 行,每行兩個數字 Ai、Bi,表示 Ai號巨魔和 Bi號巨魔之間有從屬關係。

【輸出格式】

輸出一個數字,即巨魔最高指揮官的編號。如果有多個輸出編號最小的那個。

【樣例輸入輸出】

bless.in
3
1 2
2 3
bless.out
2

【樣例解釋】

1 在圖中去掉後,剩下的連通塊點數最多的爲 2 個。2 在圖中去掉後,剩下的連通塊點
數最多的爲 1 個,3 在圖中去掉後,剩下的連通塊點數最多爲 2 個。

【數據範圍】

20%的數據 1N1000
100%的數據 1N106

【題解】

首先無向圖轉有向圖;
當一個點被刪掉之後,產生的連通塊有:
一:此點上方的所有點。
二:以此點的每一個兒子爲根的子樹。
然後就可以愉快的AC了。

【代碼】

#include <cstdio>
#include <cstring>
#include <algorithm>

#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
typedef long long LL;
const int size = 1000000+10;


template< typename Type >inline void Read( Type &In ){
    In=0;char ch=getchar();
    for( ;ch> '9'||ch< '0';ch=getchar() );
    for( ;ch>='0'&&ch<='9';ch=getchar() )In = In*10 + ch-'0';
}


int n,cnt;
int nxt[size<<1],head[size<<1],val[size<<1],f[size<<1];
int maxn=0x3f3f3f3f,ans;


void add_edge(int x,int y) {
    nxt[cnt]=head[x];val[cnt]=y;head[x]=cnt++;
}

namespace my_dfs {
    void dfs(int now,int pre) {
    f[now]=1;int Maxn=-1;
    for(int i=head[now];i!=-1;i=nxt[i])
        if(val[i]!=pre){
        dfs(val[i],now);f[now]+=f[val[i]];
        Maxn=Max(Maxn,f[val[i]]);
        }
    Maxn=Max(Maxn,n-f[now]);
    if(maxn>Maxn){
        maxn=Maxn;
        ans=now;
    }
    }
}

int main() {
    freopen("bless.in","r",stdin);
    freopen("bless.out","w",stdout);
    memset(head,-1,sizeof head);
   Read(n);
    for(int i=1;i<n;i++) {
    int x,y;Read(x);Read(y);
    add_edge(x,y);add_edge(y,x);
    }
    my_dfs::dfs(1,0);
    printf("%d\n",ans);
    return 0;
}

3.大地母親在忽悠着你(cheat.pas/c/cpp)

Time Limit:1s Memory Limit:256MB

【題目描述】

大地母親在護佑着你……
……
對不住了,我不想寫背景了。
……
某牛頭人:願大地母親寬恕你的罪行……
……
如何得到寬恕?
……
某牛頭人:計算mi=1nmodi 的值。
……
大地母親你真在忽悠我……

【輸入格式】

第一行 2 個數字 M、N。

【輸出格式】

輸出一個數字,即答案。

【樣例輸入輸出】

cheat.in
5 3
cheat.out
7

【樣例解釋】

3mod1=0
3mod2=1
3mod3=0
3mod4=3
3mod5=3
答案爲 1+3+3=7

【數據範圍】

20%的數據 1N,M106
100%的數據 1N,M109

【題解】

原題:[CQOI2007]餘數求和
他們那些AK的人的做法暴力分塊求,而我當時的一個數學方法後面竟然TLE了.
這裏給出一個AC的數學方法
找規律可知:f(i+1)=kmod(i+1)=kq(i+1)=kqiq=f(i)q (一個顯然的等差數列遞推式);
也就是說兩個相鄰的自然數,若被k除的商相同,則被k取模後的兩個數相差-q。
所以,只要找出一個區間[i,j],使得k/i=k/(i+1)=…=k/j,即可用等差數列公式求出kmodi+kmod(i+1)+...+kmodj
這個任務就是:解方程[k/x]=p。
可以輕易得到pxk<(p+1)x ,而我們只關注pxk ,即xkp ,得出x=[kp]
對於每一個i,令p=[k/i],q=kmodi,j=min(n,kp)
根據等差數列公式得到kmodi+...+kmodj=q(ji+1)(ji+1)(ji)2p

【代碼】

#include <cstdio>
#include <cstring>
#include <algorithm>

typedef long long LL;

LL ans,n,k,p,q;

inline LL read() {
    LL in=0;char ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar())
        in=in*10+ch-'0';
    return in;
}

int main() {
    freopen("cheat.in","r",stdin);
    freopen("cheat.out","w",stdout);
    n=read();k=read();
    for(LL i=1; i<=n; i++) {
        p=k/i,q=k%i;
        LL j=p?k/p:n;
        if(j>n)j=n;
        ans+=q*(j-i+1)-(j-i+1)*(j-i)/2*p;
        i=j;
    }
    printf("%lld\n",ans);
    return 0;
}

總結

排名 名稱  bless cheat ancestors  總分
1  Lcy  100   100  100    300
1  Yzy  100   100  100    300
1  yyj  100   100  100    300

%%%%%% mod mod mod

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