2019.10.26 CSP%您賽第三場

\(CSP\)涼心模擬^_^

——題源\(lqx、lhc\)等各位蒟蒻

題目名稱 比賽 傳遞消息 開關燈
源文件名 \(competition.cpp\) \(message.cpp\) \(light.cpp\)
輸入文件名 \(competition.in\) \(message.in\) \(light.in\)
輸出文件名 \(competition.out\) \(message.out\) \(light.out\)
測試點時限 \(1s\) \(1s\) \(2s\)
內存限制 \(256MB\) \(256MB\) \(256MB\)
題目分值 \(100\) \(100\) \(100\)
測試點個數 \(10\) \(10\) \(10\)
測試點分值 \(10\) \(10\) \(10\)
題目類型 傳統 傳統 傳統

說明:ios

\(1\).代碼長度限制爲 \(10KB\),編譯時開啓 \(-O2\) 開關。算法

\(2.\)請將本身的代碼按照要求放入文件夾內。測試

\(3.\)請注意不要由於非技術因素致使程序沒法正常經過數據,其中你要注意到的包括但不限於:優化

\((1).\)內存使用狀況。spa

\((2).\)是否使用文件輸入輸出,文件輸入輸出的\(.in/.out\) 的文件名是否正確,源程序的文件名是否正確。源程序的文件名和\(.in/.out\) 的文件名是否有不可見字符,若是有,則認爲文件名錯誤,不能得分。調試

\((3).\)保存文件的路徑是否正確。code

\((4).\)是否刪除調試信息。排序

\((5).\)是否能經過全部樣例。內存

\((6).\)輸出格式是否正確。字符串

\((7).\)變量類型是否正確。

\((8).\)考試結束後請不要在考場周圍疾跑、翻滾、受身、空躍、吼叫、捉雲手、豪龍破軍、千斤墜、星落、亂射、仙人指路、換位、瞬間移動、亂雷、清掃、重力加速拍、討論。

\((9).\)請注意沒有樣例解釋。本身弄去。(暴躁蒟蒻在線坑人)

\((10).\)引言&題目背景

咱們的 故事開始在一個晴朗的下午。榮耀聯盟(注:某電競組織)的當家選手們站在頒獎臺上合照,慶祝新賽季的結束。

「哎我說蘇妹子你往左一點擋到我了本劍聖場場比賽千萬上下的臉怎麼能被你擋住那邊點把四亞擠一邊去……」有個聲音在後面喋喋不休,咱們只能看到一個黃頭髮的腦殼——職業選手黃少天。

「行了,少天。安靜點。」一個溫和的聲音。「回去加訓。站哪不都同樣。」

「唔。蘇隊。這裏。」周澤楷在招手叫人過去。

「行了,沐橙。跟着哥有肉吃。「葉修摟太小姑娘的肩膀,很欠揍地笑笑。

遠處的姑娘在鎂光燈下笑得燦爛,這是咱們的第一個主角,也就是剛纔說的蘇妹子——蘇沐橙。她不說話,只是看着他們——咱們剩下的主角——剛纔提到的他們。「不管世界如何,」她想。「至少還有大家。不一樣的大家。」

倒是同樣的榮耀。


當大家作到這場比賽,可能上面這些的做者已經退役。可是不管如何,不管大家從此要在這條路上走多遠,不管會什麼時候停步,都請你回頭 看看來時的路,那裏有你的——咱們的——榮耀。

題目背景源《全職高手》。

以上。


比賽

題目背景

衆所周知,蘇沐橙是咱們的聯盟女神。如今咱們站在全明星賽的團隊賽場上。雙方選手被分紅了兩組,只要有一方獲勝,他們就更有可能得到蘇沐橙的傾心——更重要的是,冠軍。

問題描述

雙方採用一局定勝負的形式。雙方選手每人有一個能力值,當雙方派上場的選手能力值一方大於另外一方時,能力值大的一方獲勝,若兩方能力值相等則平局。但不幸的是,任意一隊上場選手抽籤決定,每隊每名選手上場機率相等。

蘇沐橙饒有興趣地看着場上的比賽。她想知道葉修帶領的一方獲勝的機率。

輸入格式

第一行一個正整數\(T\),表示數據組數。\((1\leq T\leq 5)\)

接下來\(T\)組數據,第一行兩個數\(N\)\(M\),分別表示葉修帶領一方人數和周澤楷一方人數。

第二行\(N\)個正整數\(a[i]\),表示葉修一方選手能力值。

第三行\(M\)個正整數\(b[i]\),表示周澤楷一方選手能力值。

輸出格式

對於每組數據輸出僅一行形如\(x/y\),表示葉修一方獲勝機率。要求輸出最簡分數。

樣例

輸入樣例

\(competition.in\)

1
3 5
4 3 7
1 9 4 6 10

輸出樣例

\(competition.out\)

1/3

數據範圍與提示

具體子任務限制及得分狀況以下表:

限制 分數佔比
葉修/周澤楷必贏(不給人點機會嗎) \(0\%\)
\(1\leq n,m\leq 2000\) \(50\%\)
\(1\leq n,m\leq 40000;1\leq a[i],b[i]\leq 10^9\) \(100\%\)

傳遞消息

題目背景

衆所周知,榮耀聯盟的職業選手們擁有本身的選手宿舍。爲了方便你們聯繫同時最大限度減小經費,每兩間宿舍之間有且只有一條簡單道路。黃少天和他的沐沐打算先到場中央,可是不幸的是,他們住的宿舍是全部宿舍當中最遠的兩間。

問題描述

如今你是聯盟主席,爲了促成這兩人的好事(什),你但願他們相遇的時間儘量短。但由於道路擁擠,全部道路的擁擠度總和必須大於等於一個值。你如今須要安排道路的擁擠程度,使得黃少天與沐沐之間的道路的擁擠度最小。

一句話題意:如今給你一棵樹,其全部邊的初始邊權爲\(0\)。給你一個值\(S\)表明新加入的邊權總和,要求你將總和爲\(S\)的邊權分給一些邊(每邊獲得的邊權能夠爲分數),要求獲得的新樹直徑最小。

注:樹的直徑:樹上最長的鏈。

輸入格式

輸入第一行包括兩個數\(n\)\(S\),其中\(n\)表示點的數目,\(S\)表示邊權總量。

接下來\(n-1\)行每行包括兩個數\(a\)\(b\),表示\(a\)\(b\)間有一條邊,保證輸入的\(a,b\)合法且不重複。

輸出格式

輸出僅一行,包括一個浮點數表示樹的直徑。這個浮點數要求精確到小數點後\(4\)位。

樣例

輸入樣例

\(message.in\)

4 3
1 2
1 3
1 4

輸出樣例

\(message.out\)

2.0000

數據範圍與提示

具體子任務限制及得分狀況以下表:

子任務 限制 分數
\(subtask1\) \(\forall b[i]=a[i]+1\) \(30\%\)
\(subtask2\) \(\forall a[i]\)相等 \(30\%\)
\(subtask3\) \(2\leq n\leq 10^5,2\leq s\leq 10^9\) \(100\%\)

開關燈

題目背景

通過一天的忙碌,葉修和他的沐沐總算回到了本身家。他們如今打算關燈休息。(咳……不是大家想的那個)

問題描述

葉修家裏一共有不少盞燈,它們構成一個\(n\times m\)的矩陣,它們均由\(0/1\)構成。其中\(0\)表示燈滅,\(1\)表示亮。咱們定義一下兩種操做:

\((1)\)將某一列\(0\)\(1\)的狀態反轉(即每盞燈的開關按一下)

\((2)\)將某兩行的狀態交換。

只有第一個操做每次記做一步。如今給定燈的初始狀態,求從這個初始狀態通過最少幾步能夠獲得結束狀態。若是不能在有限步內獲得結果,輸出\(Impossible\)

輸入格式

第一行有一個整數\(T\),表示有多少組測試數據。

每組測試數據包含三行。第一行爲兩個整數\(n, m\)

每組數據的第二行爲\(n\)個長度爲\(m\)\(0/1\)字符串,依次描述起初每行的燈的開關狀態。第\(i\)個字符串的第\(j\)個字符如果\(1\),表示對應位置的燈是亮的;\(0\)表示是滅的。

每組數據的第三行爲\(n\)個長度爲\(m\)\(0/1\)字符串,描述但願達到的全部燈的開關狀態。格式同上。

輸出格式

輸出\(T\)行,依次爲每組測試數據的答案。若是不可能達到,輸出\(Impossible\);不然輸出最少按多少次開關。

樣例

輸入樣例

\(light.in\)

3
3 2
01 11 10
11 00 10
2 3
101 111
010 001
2 2
01 10
10 01

輸出樣例

\(light.out\)

1
Impossible
0

數據範圍與提示

具體子任務限制及得分狀況以下表:

限制 分數佔比
注意。沒有部分分。 \(0\%\)
\(n\leq 10^3;m\leq 50\) \(100\%\)

\(Prob1\) 比賽

算法1

在第一部分數據中,有\(1\leq n,m\leq 2000\),因此暴力枚舉每組可能的出場,統計葉修\(/\)周澤楷隊的輸贏便可。

時間複雜度\(O(nm)\)。指望得分\(50pts\)

算法2

考慮優化掉一部分狀態。咱們容易知道,當葉修\(/\)周澤楷一方派出選手\(A\),另外一方派出選手\(B\)且選手\(A\)能夠贏時,全部能力值比\(A\)高的選手均可以贏\(B\)

因此考慮將兩個給定的序列從小到大排序。對於\(A\)隊每一個人,找到第一個\(B\)隊中比\(A\)能力值高的選手,則不需考慮\(B\)隊中其他選手與\(A\)的狀況。複雜度\(O(nlogn)\)。指望得分\(100pts\)
\(std:\)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=40001;
int T,n,m,a[MAXN],b[MAXN];
int gcd(int a,int b){if(!b) return a;return gcd(b,a%b);}
void solve(){
    n=read(),m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    sort(a+1,a+n+1);
    for(int i=1;i<=m;i++) b[i]=read();
    sort(b+1,b+m+1);
    int l=0,fz=0;
    for(int i=1;i<=n;i++){
        while(l<m&&b[l+1]<a[i]) l++;
        fz+=l;
    }
    int fm=n*m;
    int Gcd=gcd(fz,fm);fz/=Gcd,fm/=Gcd;
    printf("%lld/%lld\n",fz,fm);return;
}
signed main(){
    freopen("competition.in","r",stdin);
    freopen("competition.out","w",stdout);
    T=read();
    while(T--) solve();
}

\(Prob2\) 傳遞消息

算法1

考慮第一個部分分,即\(\forall b[i]=a[i]+1\),容易知道原樹是一條鏈。因此不管如何分配\(S\)的邊權總量,樹的直徑必定是\(S\),則輸出\(S\)便可。

時間複雜度\(O(1)\)。指望得分\(30pts\)

算法2

考慮第二個部分分,即\(\forall a[i]=1\),則原圖是一個菊花圖(注:菊花圖:只有兩層節點的樹)。則容易知道全部可能的最長鏈必定通過惟一的一個\(a[i]\),則考慮將\(S\)平均分配給每條鏈再乘以2便可。

時間複雜度\(O(1)\)。指望得分\(30pts\),加上算法一共\(60pts\)

算法3

對於一整棵樹,容易知道在無負權邊的狀況下,樹的直徑的兩個端點必定都是葉子節點。而容易知道,與每一個葉子節點直接相鄰的邊對答案所作的貢獻在全部邊中必定是最少的(容易明白給靠近葉子節點的邊一個較大的權必定比給中間某一條邊一個較大的權划算)。

\(proof:\)

容易知道,由於整棵樹的邊權都是咱們本身分配的,因此對於全部得到邊權的邊,容易證實它們得到的全部邊權相等;

設咱們這棵樹一共有\(l\)個葉子節點,則若賦給全部與葉子節點相鄰的邊邊權,每條邊得到的邊權是
\(\frac{S}{l}\)。則易知樹的直徑是\(\frac{2S}{l}\)

當咱們增長一條得到邊權的邊,則每條邊得到的邊權爲\(\frac{S}{l+1}\),則由於每一個葉子節點對應着一條有邊權的邊,則樹的直徑一定通過三條有邊權的邊,則樹的直徑爲\(\frac{3S}{l+1}\),可知當\(l\geq 2\)\(\frac{2S}{l}\geq \frac{3S}{l+1}\),而由於該樹至少須要有\(3\)層節點(用以保證樹的直徑爲兩個葉子節點之間的距離),因此第一種構造方法是最優的構造方法,故上述構造方法成立。

\(:\)對於\(l\)個葉子節點,分給每條與葉子節點相鄰的邊\(\frac{S}{l}\)邊權,則樹的直徑爲\(\frac{2S}{l}\)

時間複雜度\(O(1)\)。指望得分\(100pts\)
\(std:\)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=500001;
int n,k,du[MAXN],ans;
int main(){
    freopen("message.in","r",stdin);
    freopen("message.out","w",stdout);
    n=read(),k=read();
    for(int i=1;i<n;i++)du[read()]++,du[read()]++;
    for(int i=1;i<=n;i++)
        if(du[i]==1) ans++;
    printf("%.4lf",2*1.0*k/ans);
}

\(Prob3\) 開關燈

根據題意,咱們知道,由於列上每一個數的變換是統一的,因此全部行上全部位置的數的變化次數相同。

考慮如何計算出這個變化次數。由於涉及到行之間的交換,咱們枚舉第一行通過數次交換後交換到了新的\(01\)矩陣的第幾行,從而能夠推出每列的開關燈次數。根據剛纔推出的每列次數進行模擬,若是模擬後每行狀態構成的集合與答案矩陣每行的狀態構成的集合等價(由於行之間能夠隨意交換),便可經過列的變換次數獲得答案。

枚舉每一行須要的複雜度爲\(O(n)\)。檢查答案須要的複雜度爲\(O(n)\)。總複雜度\(O({n^2})\)。指望得分\(100pts\)
\(std:\)

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<ctime>
#include<climits>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=160,L=60;
char ch[N][L];
ll n,l,a[N],b[N],tmp,c[N]; 
int main()
{
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout);
    ll i,j,k,T,ans,cnt;
    scanf("%lld",&T);
    while(T--)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        scanf("%lld%lld",&n,&l);
        ans=l+1;
        for(i=1;i<=n;i++) scanf("%s",ch[i]+1);
        for(i=1;i<=n;i++) for(j=1;j<=l;j++) a[i]=a[i]*2+ch[i][j]-'0';
        for(i=1;i<=n;i++) scanf("%s",ch[i]+1);
        for(i=1;i<=n;i++) for(j=1;j<=l;j++) b[i]=b[i]*2+ch[i][j]-'0';
        sort(b+1,b+n+1);
        sort(a+1,a+n+1);
        for(i=1;i<=n;i++)
        {
            tmp=a[1]^b[i],cnt=0;
            for(j=1;j<=n;j++) c[j]=a[j]^tmp;
            while(tmp) tmp-=(tmp&(-tmp)),cnt++;
            sort(c+1,c+n+1);
            for(j=1;j<=n;j++) if(c[j]!=b[j]) break;
            if(j==n+1) ans=min(ans,cnt);
        }
        for(i=1;i<=n;i++) if(a[i]!=b[i]) break;
        if(i==n+1) ans=0;
        if(ans==l+1) printf("Impossible\n");
        else printf("%lld\n",ans);
    }
    return 0;
}
相關文章
相關標籤/搜索