第五屆合肥工業大學宣城校區程序設計大賽題解


問題 A: 小問題

時間限制: 1 Sec  內存限制: 128 MB  Special Judge

 

題目描述

林喵喵特別喜歡解決女孩子們提出的問題. 

於是, 有一天殷老師問了林喵喵一個小問題.
 
給出一個非空有限集合A, 其中包含元素若干, 給出一個元素p, 輸出集合A的非空子集且元素p不屬於那個子集.(即要求是A的非空子集並其中不存在元素p,輸出所以符合要求的集合)
元素皆為整數,且 <=231-1

 

輸入

第一行T表示測試組數
第二行有一個數N, 表示集合A內元素的數量 Card(A) N≤20
第三行有N個集合A的元素,以空格分隔
第四行有一個A的元素p

 

輸出

 

為了降低難度, 你只需要輸出每個集合內數字的數量與總和,  總和小於231-1
每個輸出的集合占用一行
每行兩個數字, 第一個數表示非空集合元素的數量, 第二個數表示非空集合元素的總和
集合之間的順序可隨意調整

 

 

樣例輸入

1 5 1 2 3 4 5 3

樣例輸出

1 1 1 2 2 3 1 4 2 5 2 6 3 7 1 5 2 6 2 7 3 8 2 9 3 10 3 11 4 12
 

水題之一。你可以用dfs搜索每一個位置的情況,或者用二進制模擬。聰明的做法是把要剔除的元素剔除掉,再輸出所有可能情況。我當初沒寫剔除的做法就判斷了,時間復雜度較高。
二進制模擬代碼:
 
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(0))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e2+10;
 8 LL val[N];
 9 int T,n,m,h,p,ct,t;
10 LL sum;
11 int main()
12 {
13     scanf("%d",&T);
14     while(T--)
15     {
16         scanf("%d",&n);
17         for(int i=1;i<=n;i++)
18             scanf("%lld",&val[i]);
19         m=(1<<n)-1;
20         scanf("%d",&p);
21         for(int i=1;i<=n;i++)
22             if(p==val[i])
23             {
24                 p=i;
25                 break;
26             }
27         for(int i=1;i<=m;i++)
28         if(((i>>(p-1))&1)==0)
29         {
30             ct=0;
31             t=0;
32             sum=0;
33             h=i;
34             while(h)
35             {
36                 t++;
37                 if(h&1)
38                 {
39                     sum+=val[t];
40                     ct++;
41                 }
42                 h>>=1;
43             }
44             printf("%d %lld\n",ct,sum);
45         }
46     }
47     return 0;
48 }
49  
View Code

 

問題 B: 統計詞頻

時間限制: 1 Sec  內存限制: 128 MB
提交: 359  解決: 22

 

題目描述

給出一段英文文字, 統計每個單詞出現的次數(忽略大小寫)
單詞字母范圍為( a~z 或 A~Z ),沒有奇怪的字符

 

輸入

第一行組數T
第二行單詞數N (N<=10000)
后面N行有N個非空的單詞

 

輸出

輸出小寫單詞和數量,單詞按照字典序排序輸出
一個單詞占一行

 

樣例輸入

1 4 hello world hello icpc

樣例輸出

hello 2 icpc 1 world 1
 

 
水題之二。寫個map對每個string進行映射,然后用迭代器從頭到尾輸出就好了。
 
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(0))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e5+10;
 8 int T,n,m,h,p,ct,t;
 9 string s;
10 map<string,LL>::iterator it;
11 int main()
12 {
13     scanf("%d",&T);
14     while(T--)
15     {
16         scanf("%d",&n);
17         map<string,LL> num;
18         for(int i=1;i<=n;i++)
19         {
20             cin>>s;
21             for(int j=0;j<s.size();j++)
22                     s[j]=tolower(s[j]);
23             num[s]++;
24         }
25         for(it=num.begin();it!=num.end();it++)
26             printf("%s %lld\n",(it->first).c_str(),it->second);
27     }
28     return 0;
29 }
View Code

 

問題 C: 機房問題

時間限制: 2 Sec  內存限制: 128 MB
提交: 214  解決: 18

 

題目描述

在你們寫題的時候,萌萌的林喵喵同學其實在暗中觀察你們(Big Miao is watching you!)

其中觀察的一項就是要統計出一段時間內哪個時刻上機人數最多。

你能否比林喵喵更快地統計出來呢?

 

輸入

T表示組數
N表示數據數量
接下來N行每行三個整數t1,t2,n
表示n個學生在t1到t2使用了機房電腦(包含t1,t2)
0<t1<t2<=10000000
0<n<=10000000

 

輸出

輸出一個時間t, 這個時刻上機人數最多
若有多個最大值則輸出最小的t

 

樣例輸入

1 3 1 2 1 1 3 1 2 5 2

樣例輸出

2

 


 
水題之三。數據范圍給的這么大,一看就不能瞎暴力。
我們只需要遍歷訪問過的時間點就行了。這相當於一個離散化的過程。
那么這個東西可以用map來快速存儲,因為map是有序的。而不用寫離散化代碼(雖然也是兩行的事)。這個看看輸入范圍nlogn一看就知道不會超時啦。
然后對於k人在一段時間[l,r]上機,在l點+k,r+1點-k。求一個前綴和,就能得出所有時間的上機人數了。
而相同人數的最靠前的時間也是在這些點中產生的。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(0))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e5+10;
 8 int T,n,h,p,ct;
 9 LL t1,t2,m,sum,maxn,pt;
10 string s;
11 map<LL,LL>::iterator it;
12 int main()
13 {
14     scanf("%d",&T);
15     while(T--)
16     {
17         scanf("%d",&n);
18         map<LL,LL> num;
19         for(int i=1;i<=n;i++)
20         {
21             scanf("%lld%lld%lld",&t1,&t2,&m);
22             num[t1]+=m;
23             num[t2+1]-=m;
24         }
25         num[0]=0;
26         maxn=0;
27         pt=0;
28         sum=0;
29         for(it=num.begin();it!=num.end();it++)
30         {
31             sum+=it->second;
32             if(sum>maxn)
33             {
34                 maxn=sum;
35                 pt=it->first;
36             }
37         }
38         printf("%lld\n",pt);
39     }
40     return 0;
41 }
View Code

 

 

問題 D: 帥寶寶的xor

時間限制: 2 Sec  內存限制: 128 MB
提交: 43  解決: 10

 

題目描述

眾所周知,帥寶寶精通圖論。這一天他剛學習了一個新操作-異或(^)。這時候林喵喵給他出了一道異或題:
起初林喵喵給出了一些數字,這些數字均不超過109。
然后林喵喵有以下兩種操作:
1 x:在這些數中加入數字x。
2 x:從所有數中找出一個數字y,使得x^y最大,並輸出這個y的值。
帥寶寶頓時感到為難,你能幫帥寶寶解決這個問題嗎?

 

輸入

多組數據(1≤T≤10),對於每組數據:
第一行有一個整數n(0≤n≤105),代表起初的數字個數。
第二行包含n個整數ai(0≤ai≤109),即起初給出的數字個數。
第三行有一個整數q(0≤q≤105),代表接下來的操作個數。
第3+i行的格式如題,其中0≤x≤109。
所有n+q≤2×105。

 

輸出

對於每個2操作輸出對應的y。
每組數據后空一行。

 

樣例輸入

3 1 2 3 5 2 1024 1 100 2 1021 2 1022 2 1024

樣例輸出

3 2 1 100

 

01型字典樹模板題。

寫過字典樹的應該都會,稍難題。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e5+10;
 8 struct Node
 9 {
10     int next[2];
11 };
12 struct Trie
13 {
14     Node node[N*33];
15     int cnt;
16     void init()
17     {
18         cnt=0;
19         clr_1(node);
20     }
21     void add(LL x)
22     {
23         int t,u=0;
24         for(int i=31;i>=0;i--)
25         {
26             t=(x>>i)&1;
27             if(node[u].next[t]==-1)
28             {
29                 node[u].next[t]=++cnt;
30             }
31             u=node[u].next[t];
32         }
33         return ;
34     }
35     LL query(LL x)
36     {
37         int t,u=0;
38         LL ans=0;
39         for(int i=31;i>=0;i--)
40         {
41             t=(x>>i)&1;
42             ans<<=1;
43             if(node[u].next[t^1]==-1)
44             {
45                 ans|=t;
46                 u=node[u].next[t];
47             }
48             else
49             {
50                 ans|=(t^1);
51                 u=node[u].next[(t^1)];
52             }
53         }
54         return ans;
55     }
56 }trie;
57 int n,m,k,t,q;
58 int main()
59 {
60     while(scanf("%d",&n)!=EOF)
61     {
62         trie.init();
63         for(int i=1;i<=n;i++)
64         {
65             scanf("%d",&k);
66             trie.add((LL)k);
67         }
68         scanf("%d",&q);
69         for(int i=1;i<=q;i++)
70         {
71             scanf("%d%d",&t,&k);
72             if(t==1)
73                 trie.add((LL)k);
74             else
75                 printf("%lld\n",trie.query((LL)k));
76         }
77         printf("\n");
78     }
79     return 0;
80 }
View Code

 

問題 E: N馬問題

時間限制: 2 Sec  內存限制: 128 MB
提交: 23  解決: 4

 

題目描述

林喵喵和冬冬下象棋的時候突然異想天開,由N數碼問題想出了一個N馬問題
給出一個n*m的棋盤, 請問至多能放多少個馬並使他們無法互相攻擊到對方
馬可以攻擊的地方為所在的坐標橫着走一步,豎着走兩步,或者橫着走兩步,豎着走兩步
不考慮象棋中馬被絆到不能走的規則,即任意馬可以走到八個地方(只要那個地方在棋盤內)
 

 

輸入

多組數據,請使用讀取多組數據的寫法
接下來有若干行,每組數據有一行,m和n,表示棋盤是m行n列的,1<=n,m<=1000

 

輸出

輸出一個數字,表示m*n棋盤最多擺放馬的數量

 

樣例輸入

1 1 5 5 2 3 4 7

樣例輸出

1 13 4 14
 

找規律題。中等難度題。怎樣擺馬數量最多?很容易發現一個大棋盤上從左上角擺起,按照2*2放馬,2*2不放馬,2*2放馬.....即(1,1)~(2,2)這個正方形放馬,然后其他無論往下還是往右每隔2*2個格子放2*2的馬,這樣的情況馬是最多的。數量為(n*m+1)/2。然而你會發現只有1行和2行的時候(或1列和2列)的時候情況是特殊的,因為他們最多一行正方形或一列正方形,沒有和下一列(下一行)共享跳躍到達點。這樣的情況需要特殊判斷輸出相應的答案。
 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4   
 5 int solve(int n, int m) {
 6     if (n < m) return solve(m, n);
 7     else if (m==1) return  n;
 8     else if (m==2) {
 9         return (n/4)*4+((n%4>1)?2:n%4)*2;
10     }
11     else return (n*m+1)/2;
12 }
13   
14 int main() {
15       
16     int r,c;
17     while (scanf("%d%d", &r, &c)!=EOF) {
18         printf("%d\n", solve(r, c));
19     }
20     return 0;
21 }
View Code

 

問題 F: xor game

時間限制: 1 Sec  內存限制: 128 MB
提交: 26  解決: 7

 

題目描述

帥寶寶覺得你們太菜啦,於是帥寶寶用他熟悉的xor操作發明了一個簡單的游戲讓你們簽到,不要辜負他的期望啊。
游戲雙方寫出他們各自長度為n由互不相同的數字組成的序列(A方)x1,x2,x3……xn和(B方)y1,y2,y3……yn。然后雙方同時亮出他們寫下的數字序列。如果所有這2n個數字中有相同的數字,則兩人進行多次以上步驟,直到這2n個數字中的數字互不相同。這時的數字序列才是游戲所需要的數字序列。
將調整過后的x序列和y序列陳列出來。計算其中滿足條件的數字對(i,j)(1≤i,j≤n)的對數。其條件為:計算xi^yj=num后,若num是這2n個數中的一個,則滿足條件。
若這樣的數字對數為偶數則游戲A方贏,否則B方贏。
現在帥寶寶充當游戲B方,林喵喵充當游戲A方,請你確定在一盤xor游戲中誰會獲勝。

 

輸入

多組數據(1≤T≤10),對於每組數據:
第一行有一個整數n(1≤n≤105),代表數字序列數字個數。
第二行含n個整數xi(1≤xi≤1017)。
第三行含n個整數yi(1≤yi≤1017)。
保證以上xi和yi這2n個數字互不相等。

 

輸出

若帥寶寶獲勝輸出"shuaibaobao"否則輸出"linmiaomiao"。

 

樣例輸入

3 10 233 322 1234567 7654321 12345678987654321 987654321 23 1 9 10 2 3 4 5 6 7 8 11 12 34 5 1 2 3 4 5 6 7 8 9 10 2 101 10 111 5

樣例輸出

linmiaomiao linmiaomiao linmiaomiao

提示

 

 xor自反性,b^a^b=a。

 


 

cf上的題,稍難的思維題吧。(畢竟已經寫了提示了)。

只不過我把范圍改大了,防止你們瞎暴力23333。

首先兩個數列內的數都完全不相同。那么任意兩個數異或的結果數列內最多只有一個數是對應的。

然后考慮異或的自反性。

如果我們xi^yj==ci(c表示x、y中任意一個數列),那么肯定有xi^ci==yj或者yj^ci==xi。這取決於c是哪個數列。

因此這樣的數對是成對出現的,有偶數個。linmiaomiao一定贏。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e5+10;
 8 int n,m,k,t,q,T;
 9 LL x[N],y[N];
10 int main()
11 {
12 //    freopen("10.in","r",stdin);
13 //    freopen("10.out","w",stdout);
14     scanf("%d",&T);
15     while(T--)
16     {
17         scanf("%d",&n);
18         for(int i=1;i<=n;i++)
19             scanf("%lld",&x[i]);
20         for(int i=1;i<=n;i++)
21             scanf("%lld",&y[i]);
22         printf("linmiaomiao\n");
23     }
24     return 0;
25 }
26  
View Code

 

問題G: 旺財的集郵策略

時間限制: 2 Sec  內存限制: 128 MB
提交: 53  解決: 3

 

題目描述

倉鼠旺財有N種不同面值的郵票(如:1 分,3 分),每種郵票都有無限多張。現在旺財想給林喵喵寄信,郵局提供的信封最大只能貼K張郵票。現在旺財想知道它能夠從1到M最大可連續貼出的郵資是多少。
例如:假設旺財有1分和3分兩種郵票;郵局的信封最多可以貼5張郵票。很容易貼出1到5分的郵資(用1分郵票貼就行了)接下來的郵資也不難:
6 = 3 + 3 
7 = 3 + 3 + 1 
8 = 3 + 3 + 1 + 1 
9 = 3 + 3 + 3 
10 = 3 + 3 + 3 + 1 
11 = 3 + 3 + 3 + 1 + 1 
12 = 3 + 3 + 3 + 3 
13 = 3 + 3 + 3 + 3 + 1
然而,無論如何讓5枚1分或者3分的郵票組合,根本不可能貼出14分的郵資。因此,對於這兩種不同面值的郵票在最大可以張貼5張的情況下,我們可以最大連續貼出的郵資就是13。
Note:因為14貼不出來,所以最高上限是13而不是15。
我們相信聰明的你一定可以幫助旺財解決問題

 

輸入

第1行:
       兩個整數,K和N,分別表示最大可以張貼的郵票數量和不同面值的郵票種數。其中K(1 <= K <= 200),N(1 <= N <= 50)
第 2 行: 
       N個整數,分別表示N個不同郵票的面值,每張郵票的面值不超過10000。

 

輸出

       一個整數,表示在不超過K張郵票的情況下從1分開始能夠最大連續可貼出的郵資是多少。

 

樣例輸入

5 2 1 3

樣例輸出

13
 

背包經典問題。開場那兩個人太凶殘了直接過了。。。
稍難題。
 1 //wanghan's code
 2 #include "iostream"
 3 #include "cstdio"
 4 #include "cstring"
 5 #include "string"
 6 using namespace std;
 7 const int maxn=2e6+100;
 8 const int INF=1<<30;
 9 int K,n;
10 int dp[maxn],v[100];
11 int main()
12 {
13     cin>>K>>n;
14     int ans=0;
15     for(int i=1;i<=n;i++){
16         cin>>v[i];
17         ans=max(ans,v[i]);
18     }
19     int m=2e6;
20     for(int i=1;i<=m;i++)
21         dp[i]=INF;
22     for(int i=1;i<=n;i++){
23         for(int j=v[i];j<=m;j++){
24             dp[j]=min(dp[j],dp[j-v[i]]+1);
25         }
26     }
27     int res=1;
28     for(int i=1;i<=m;i++){
29         if(dp[i]>K){
30             res=i; break;
31         }
32     }
33     cout<<res-1<<endl;
34 }
View Code

 

問題 H: 網絡收費

時間限制: 1 Sec  內存限制: 64 MB
提交: 30  解決: 3
 

題目描述

    網絡已經成為當今世界不可或缺的一部分。每天都有數以億計的人使用網絡進行學習、科研、娛樂等活動。然而,不可忽視的一點就是網絡本身有着龐大的運行費用。所以,向使用網絡的人進行適當的收費是必須的,也是合理的。
 
 
 
    假設有這樣一個網絡:網絡中的用戶一共有2N個,編號依次為1, 2, 3, …, 2N。這些用戶之間是用路由點和網線組成的。用戶、路由點與網線共同構成一個滿二叉樹結構。樹中的每一個葉子結點都是一個用戶,每一個非葉子結點(灰色)都是一個路由點,而每一條邊都是一條網線。
 
 
而網絡公司對應該網絡的收費方式比較奇特,稱為“配對收費”。即對於每兩個用戶i, j (1≤i < j ≤2N ) 進行收費。
 
 
 
    由於用戶可以自行選擇兩種付費方式A、B中的一種,所以網絡公司向學校收取的費用與每一位用戶的付費方式有關。該費用等於每兩位不同用戶配對產生費用之和。 為了描述方便,首先定義這棵網絡樹上的一些概念:
 
 
 
    祖先:根結點沒有祖先,非根結點的祖先包括它的父親以及它的父親的祖先;
 
 
 
    管轄葉結點:葉結點本身不管轄任何葉結點,非葉結點管轄它的左兒子所管轄的葉結點與它的右兒子所管轄的葉結點;
 
 
    距離:在樹上連接兩個點之間的用邊最少的路徑所含的邊數。
   對於任兩個用戶i, j (1≤i):
 
 
    如果他們最近公共祖先下選擇A的人數大於B的人數,那么只對選擇A的用戶收費,費用為Fi,j(即兩人中選擇A的有k人,則兩人配對收費為k*Fi,j),否則只對選擇B的用戶收費,費用仍為Fi,j。
 
 
 
    由於最終所付費用與付費方式有關,所以用戶們希望能夠自行改變自己的付費方式以減少總付費(所有人的付費和)。然而,由於網絡公司已經將每個用戶注冊時所選擇的付費方式記錄在案,所以對於用戶i,如果他/她想改變付費方式(由A改為B或由B改為A),就必須支付Ci元給網絡公司以修改檔案(修改付費方式記錄)。
 
 
 
    現在的問題是,給定每個用戶注冊時所選擇的付費方式以及Ci,試求這些用戶應該如何選擇自己的付費方式以使得在支付給網絡公司的總費用最少(更改付費方式費用+配對收費的費用)。
 
 
 
    注:配對收費並不是說對i結點只選擇一個結點與其配對收費,而是對i和所有其他結點都進行配對收費。

 

輸入

    輸入第一行有一個正整數N。
    第二行有2N個整數,依次表示1號,2號,…,2N號用戶注冊時的付費方式,每一個數字若為0,則表示對應用戶的初始付費方式為A,否則該數字為1,表示付費方式為B。
    第三行有2N個整數,表示每一個用戶修改付費方式需要支付的費用,依次為C1, C2, …,CM 。( M=2N ) 以下2N-1行描述給定的兩兩用戶之間的流量表F,總第(i + 3)行第j列的整數為Fi, j+i 。(1≤ i < 2N,1 ≤ j ≤ 2N-i) 所有變量的含義可以參見題目描述。N≤10,0≤Fi, j≤500,0≤Ci≤500 000

 

輸出

你的程序只需要向輸出文件輸出一個整數,表示支付給網絡公司的最小總費用。(單位:元)

 

樣例輸入

2 1 0 1 0 2 2 10 9 10 1 2 2 1 3

樣例輸出

8

noi2006的原題,某位陳瑜希的論文題。詳見我 樹形dp系列題解。
一道樹上背包,也可以多叉轉二叉去做。
防ak題,高難度題。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define clrmax(x) memset(x,0x3f3f3f3f,sizeof(x))
 5 #define mod 1000000007
 6 #define LL long long
 7 using namespace std;
 8 const int maxN=5e3+10;
 9 int f[maxN][maxN];
10 int flow[maxN][maxN];
11 int c[maxN];
12 int cost[maxN][20],fa[maxN][20];
13 bool chose[maxN];
14 int N,n,m,k,ans,p;
15 int dfs(int u,int dep,int sta)//sta前從右往左第dep+1位開始是該結點分配的B方式的數量,1~dep位為其祖先結點na和nb的大小相對關系,表現為B收費為1,A收費為0。
16 {
17     if(f[u][sta]!=0x3f3f3f3f) return f[u][sta];
18     int num=sta>>dep;
19     int fasta=sta^(num<<dep);
20     //該結點的收費選擇chos
21     int chos=(1<<(N-dep))-num>=num?1:0;
22     //葉子結點處理返回
23     if(dep==N)
24     {
25         int v=u-(n-1);
26         fasta<<=1;
27         fasta|=chos;
28         if(num^chose[v])
29             f[u][sta]=c[v];
30         else
31             f[u][sta]=0;
32         for(int i=N;i>=0;i--)
33         {
34             if(!((fasta&1)^num))
35                 f[u][sta]+=cost[v][i];
36             fasta>>=1;
37         }
38         return f[u][sta];
39     }
40     //約束左右結點取B的數量在合理范圍內,並選擇其中最小的一個和。
41     int minx=max(0,num-(1<<N-dep-1));
42     int maxx=min(num,1<<N-dep-1);
43     for(int i=minx;i<=maxx;i++)
44         f[u][sta]=min(dfs(u<<1,dep+1,(i<<dep+1)|(fasta<<1|chos))+dfs(u<<1|1,dep+1,(num-i<<dep+1)|(fasta<<1|chos)),f[u][sta]);
45     return f[u][sta];
46 }
47 int main()
48 {
49     scanf("%d",&N);
50     n=1<<N;
51     for(int i=1;i<=n;i++)
52     {
53         scanf("%d",&p);
54         chose[i]=p;
55     }
56     for(int i=1;i<=n;i++)
57         scanf("%d",&c[i]);
58     for(int i=1;i<=n;i++)
59         for(int j=i+1;j<=n;j++)
60             scanf("%d",&flow[i][j]);
61     //計算子結點i(樹上編號為i+n-1)在深度為j的祖先
62     for(int i=1;i<=n;i++)
63     {
64         k=i+n-1;
65         for(int j=N;j>=0;j--)
66         {
67             fa[i][j]=k;
68             k>>=1;
69         }
70     }
71     clr(cost);
72     //若i,j在深度為k處祖先相同,那末將流量費用flow[i,j]加到i和j在深度k所需要的費用中。
73     for(int i=1;i<=n;i++)
74         for(int j=i+1;j<=n;j++)
75             for(int k=N;k>=0;k--)
76                 if(fa[i][k]==fa[j][k])
77                 {
78                     cost[i][k]+=flow[i][j];
79                     cost[j][k]+=flow[i][j];
80                     break;
81                 }
82     clrmax(f);
83     ans=0x3f3f3f3f;
84     for(int i=0;i<=n;i++)
85         ans=min(ans,k=dfs(1,0,i));
86     printf("%d\n",ans);
87     return 0;
88 }
View Code

 

問題 I: 簽到題

時間限制: 5 Sec  內存限制: 16 MB
提交: 241  解決: 18
 

 

題目描述

眾所周知,冬學姐人見人愛,因此他的仰慕者們分布在世界各地。有一天冬學姐心血來潮想要去見他的所有仰慕者。
假設冬學姐所有仰慕者所在城市排成一條直線,總共有n座城市,編號為0,1,2......n-1,從城市i到城市j飛機票所需要的費用為(i+j)%n。而冬學姐剛開始在0號城市中。
因為冬學姐特別喜歡飛機,所以非飛機不搭乘。可是冬學姐囊中羞澀,希望以最少的費用見到他的所有仰慕者。你能幫冬學姐設計一個方案,使得他見到所有仰慕者所需費用最少嗎?

 

輸入

多組數據,數據不超過1000000組。對於每組數據包含一個整數,代表冬學姐的仰慕者所在城市個數n(0≤n≤1018)。

 

輸出

對於每組數據,輸出它的數據編號(從1開始),以及冬學姐最少需要的費用。

 

樣例輸入

0 1 2

樣例輸出

Case 1: 0 Case 2: 0 Case 3: 1

來源


水題之四。cf上的題。
0號結點獨立一組。1和n-1號結點一組,之間建一條邊這條邊是權值為0(不收費)的。然后是2和n-2,3和n-3....(n+1)/2-1和(n+1)/2(n為奇數)或n/2(n為偶數).這樣一共有n/2組之間是不需要收費的。然后0和1,建邊,2和n-1建邊,3和n-2建邊。。這樣建n/2條權值為1的邊修構成了最終的圖。我們只需要花費n/2的費用就能從結點0遍歷整個圖。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 int main()
 8 {
 9     int kase=0;
10     LL n;
11     while(scanf("%lld",&n)!=EOF)
12         printf("Case %d: %lld\n",++kase,n>>1);
13     return 0;
14 }
View Code

 

問題 J: 水題

時間限制: 1 Sec  內存限制: 128 MB
提交: 11  解決: 2
 

 

題目描述

是的,這是一道有關流的問題。
給出一個由n個結點組成的有向圖,這n個結點標號為0~n-1。
對於任意滿足(0≤i<j<n)的結點對(i,j),都存在一條從結點i連向結點j的有向邊,其容量為i^j(i異或j)。
請你構建從結點0到結點n-1的最大流網絡,並輸出其最大流。為簡化輸出,輸出答案 mod 109+7。

 

輸入

多組數據,數據不超過10000組。每組數據包含一個整數n,代表有向圖結點個數(2≤n≤1018)。

 

輸出

對於每組數據,輸出它的最大流 mod 109+7后的答案。

 

樣例輸入

2

樣例輸出

1
 

 
某網絡賽題目。較難難度的找規律題。
運用最大流最小割定理可以推出其規律。當然我當初是打表硬找規律的233333。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define LL long long
 4 #define mod 1000000007
 5 using namespace std;
 6 LL quick_pow(LL x, LL n) {
 7     LL res = 1;
 8     x=(x%mod+mod)%mod;
 9     while(n) {
10         if(n&1)
11             res=res*x% mod;
12         n >>=1;
13         x =x*x% mod;
14     }
15     return res;
16 }
17 int main()
18 {
19     LL n,m,q,l,ans,k,kk;
20     int t;
21     while(scanf("%lld",&n)!=EOF)
22     {
23         t=0;
24         n--;
25         m=n;
26         while(m)
27         {
28             t++;
29             m>>=1;
30         }
31         q=1;
32         m=(q<<(t-1));
33         ans=(m%mod)*((1+m)%mod)%mod;
34         ans=ans*quick_pow(2,mod-2)%mod;
35         n-=m;
36         kk=1;
37         k=2;
38         while(k<=n+kk)
39         {
40             ans=(ans%mod+(((n+kk)/k)%mod)*((kk%mod)*(kk%mod)%mod+1)%mod)%mod;
41             if(k==LLONG_MAX)
42                 break;
43             kk=k;
44             k<<=1;
45         }
46         printf("%lld\n",ans);
47     }
48     return 0;
49 }
View Code

 

問題 K: 臨界區資源問題

時間限制: 1 Sec  內存限制: 128 MB
提交: 404  解決: 53
 

 

題目描述

15級有一位李軒大佬,對你沒看錯就是坐在第二機房的那個。最近正在學操作系統,他遇到了一個問題。可是他今天得來比賽啊,所以沒時間解決這個問題,希望你能幫他解決:
在操作系統中,多個進程必須互斥地訪問臨界區的資源。
簡單地說,就是當一個進程A在訪問一個臨界區資源時,另外一個進程B是不能訪問該資源的。
 
考慮有n個臨界區資源,編號為0~n-1。剛開始都處於沒有進程占用(訪問)的空閑狀態。
現在順序地給出m條訪問指令,編號1~m(沒有退出訪問指令,即一旦訪問就一直處於訪問狀態),每個指令只包含一個數k,代表訪問的臨界區資源編號,並且發出每條指令的進程都互不相同。
如果有某條指令是無效的,即在它之前有其它指令訪問該資源,則跳過該條指令,並輸出該指令編號。
例如:
n=10,m=10。
m條指令分別是:2 3 5 4 1 2 3 4 5 6。第六條指令訪問的2號資源在第一條指令時就被其他進程占用了,同理第七條請求訪問的3號資源第二條指令時已經被占用。相同地第八條第九條指令也是無效的。
因此輸出6 7 8 9。
好吧說了這么多,其實題意就是:
給出一個長度為m的數列,該數列中數字的取值范圍是0~n-1。對於某個位置i有數字ai,如果在i之前出現了和i位置數字ai值相等的數字,則需要輸出i。

 

輸入

一組數據。
第一行有兩個正整數n、m(1≤n,m≤100)。代表資源個數和訪問指令個數。
第二行包含m個整數,代表第i條指令訪問的資源ai。

 

輸出

輸出一行,按上升順序輸出無效指令編號。

 

樣例輸入

10 10 2 3 5 4 1 2 3 4 5 6

樣例輸出

6 7 8 9

 


 

 

真簽到題,比以上水題還水。

就是題目很忽悠23333,然而這是連兩個for都能過的題。當初預期是所有寫題的人都能過。

然而還是有人糾結前面問題而沒看后面問題。導致過題人數只有一半。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e2+10;
 8 int n,m;
 9 int a[N],b[N];
10 int main()
11 {
12     scanf("%d%d",&n,&m);
13     clr(b);
14     for(int i=1;i<=m;i++)
15     {
16         scanf("%d",&a[i]);
17         if(b[a[i]])
18         {
19             printf("%d ",i);
20         }
21         else
22         {
23             b[a[i]]=1;
24         }
25     }
26     printf("\n");
27     return 0;
28 }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM