【學長出題】【比賽題解】17-10-18

此次比賽由@FallDream學長出題,歡迎去他的blog學習!ios

【T1】切課本數組

題意:學習

小 Z 厭惡數學,他決定將數學課本切成一塊一塊的。他的課本是一個 n*m 的矩形,小 Z 決定切 K 刀,每刀他能夠橫着切或者豎着切,可是切成的矩形的長和寬都必須是整數。固然,小 Z 不會作出兩次相同的操做。例如 n=6,m=4,k=3 時,如下是一種合法的切法。ui

不巧的是,小 Z 的數學老師知道了他這個行爲,而且刁鑽的老師確定會找到切出的矩形中面積最小的那一塊來 D 他, 因此小 Z 想知道最優狀況下面積最小的那一塊麪積最大能是多少?spa

輸入:code

輸入數據只包含一行三個整數 n,m,k,含義如題目所述。blog

輸出:get

輸出一個數字,表示答案。 若是沒有合法的方案,輸出-1。數學

題解:string

固定一個方向的刀數的時候,確定是儘可能平均切。
若是能只切一邊的話,只切一邊必定最優。
假設 n<=m, k>=m 時,考慮將一邊所有切開,剩下的平均切到另外一邊。
長的邊切 m-1 刀,另外一邊切 k-(m-1)刀必定最優,由於, n/(k-(n-1))>=m/(k-(m-1))。

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 inline int read()
 5 {
 6     int x=0,f=1;char ch=getchar();
 7     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 9     return x*f;
10 }
11 int n,m,k;long long ans=0;
12 int main()
13 {
14     freopen("cut.in","r",stdin);
15     freopen("cut.out","w",stdout);
16     n=read();m=read();k=read();
17     if(n+m-2<k) return 0*puts("-1"); 
18     for(int i=1,last;i<=n;i=last+1)
19     {
20         last=n/(n/i);int j=min(last,k+1);
21         if(j>=i) ans=max(ans,1LL*(n/j)*(m/(k-(j-1)+1)));
22     }
23     printf("%lld\n",ans);
24     return 0;
25 }

【T2】海棠數組

題意:

小 Z 最喜歡數組了,如今他獲得了由 n 個正整數組成的數組 ai。
他想構造一個相同大小的正整數數組 bi 知足兩個數組的差別度\(\sum_{i=1}^{n}|a_{i}-b_{i}|\)最小。
特殊的是, bi 數組的全部元素必須知足兩兩互質。

輸入:

第一行一個數 n, 表示數組大小。
接下來一行 n 個正整數 ai, 表示給定的數組。(1<=ai<=30)

輸出:

輸出一行 n 個正整數 bi,表示答案。
輸出的數字必須知足 1<=bi<=10^9。若是有多個答案,你能夠輸出任意一個。

題解:

ai<=30,那麼,若是選取的bi大於58,能夠換成1,而答案不會更劣。
因此1<=bi<=58,再考慮互質的條件,說白了就是質因數不能重複,而58之內的質數只有16個,故使用狀壓DP。
用 f[i][j] 表示前 i 個數中,選取了集合 j 中的質數。用 fcts[i] 表示 i 的質因子集合。
有 f[i][j]=min( f[i-1][j\fcts[k]] + |ai-k| )。其中k取遍1到58。預處理出fcts加快速度。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<string>
 7 #define ll long long
 8 #define mem(qaq,x) memset(qaq,x,sizeof(qaq))
 9 #define For(i,a,b) for (int i=a; i<=b; i++)
10 #define Ford(i,a,b) for (int i=a; i>=b; i--)
11 #define File(fn) freopen(fn".in","r",stdin);freopen(fn".out","w",stdout);
12 using namespace std;
13 
14 const int fcts[59]={0,0,1,2,1,4,3,8,1,2,5,16,3,32,9,6,1,64,3,128,5,10,17,256,3,4,33,2,9,512,7,1024,1,18,65,12,3,2048,129,34,5,4096,11,8192,17,6,257,16384,3,8,5,66,33,32768,3,20,9,130,513};
15 int n,a[101],f[101][65536];
16 short g[101][65536],ans[101];
17 
18 inline int Abs(int x){return x<0?-x:x;}
19 
20 void init(){
21     scanf("%d",&n);
22     For(i,1,n) scanf("%d",a+i);
23 }
24 
25 void dp(){
26     memset(f,0x3f,sizeof f);
27     f[0][0]=0;
28     For(i,1,n){
29         For(j,0,65535){
30             For(k,1,58){
31                 if((fcts[k]&j)!=fcts[k]) continue;
32                 if(f[i][j]>f[i-1][j^fcts[k]]+Abs(a[i]-k)){
33                     f[i][j]=f[i-1][j^fcts[k]]+Abs(a[i]-k);
34                     g[i][j]=k;
35                 }
36             }
37         }
38     }
39 }
40 
41 int main(){
42     File("array");
43     init();
44     dp();
45     int x=-1, y=-1, s=99999999;
46     For(j,0,65535) if(f[n][j]<s) s=f[n][j], x=g[n][j], y=j;
47     ans[n]=x;
48     Ford(i,n-1,1){
49         s=99999999;
50         ans[i]=g[i][y^fcts[x]], y=y^fcts[x], x=ans[i];
51     }
52     For(i,1,n) printf("%d ",ans[i]);
53     return 0;
54 }

【T3】修路

題意:

L 國包含 n 個城市和 m 條雙向道路,第 i 條道路鏈接 ui,vi 兩個城市, 距離爲ti,這些道路將全部 n 個城市鏈接在一塊兒。 明年, L 國將會在首都,也就是 1 號城市舉辦一年一度的 NOI,因此 L 國的國王委託小 Z 新建一些道路來減小一些城市到達首都的距離。小 Z 很快修好了道路,可是他卻不是很滿意。他想知道最多能夠少新建多少道路,知足首都到全部城市的最短路長度和如今相同。

輸入:

第一行讀入三個數字 n,m,k,依次表示城市的數量,原有道路的數量和新建道路的數量。
接下來 m 行,每行三個數字 ui,vi,ti,表示一條原有的道路
最後 k 行,每行兩個數字 si,wi,表示一條新建的道路鏈接 1 和 si,距離爲 wi。

輸出:

輸出一個整數,表示最多能少修建多少條新建的道路 。

題解:

把全部新加的邊去個重,到相同的點的邊只保留一個最小的,而後跑一次最短路。
一條新加的邊若是長度不是最短路必定能夠去掉,不然只有知足有其它最短路徑到達這個點的時候才能夠去掉。
算出到每一個點最短路條數是否大等於 2 便可。
複雜度 O((n+k)logn)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<string>
 7 #include<queue>
 8 #define ll long long
 9 #define mem(qaq,x) memset(qaq,x,sizeof(qaq))
10 #define For(i,a,b) for (int i=a; i<=b; i++)
11 #define Ford(i,a,b) for (int i=a; i>=b; i--)
12 #define File(fn) freopen(fn".in","r",stdin);freopen(fn".out","w",stdout);
13 using namespace std;
14 
15 inline int in(){
16     int x=0,f=1;
17     char ch=getchar();
18     while (ch<'0'||ch>'9')f=ch=='-'?0:1,ch=getchar();
19     while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
20     return f?x:-x;
21 }
22 
23 typedef pair<int,int> P;
24 
25 int n,m,k,ans;
26 int h[50001],nxt[500001],to[500001],w[500001],tot=0;
27 inline void ins(int x,int y,int z){nxt[++tot]=h[x];to[tot]=y;w[tot]=z;h[x]=tot;}
28 int dis[50001],num[50001];
29 int kkkk[50001];
30 priority_queue<P,vector<P>,greater<P> > pq;
31 
32 void init(){
33     int x,y,z;
34     n=in(); m=in(); k=in();
35     For(i,1,m){
36         x=in(), y=in(), z=in();
37         ins(x,y,z);
38         ins(y,x,z);
39     }
40     For(i,1,k){
41         int y=in(), z=in();
42         if(!kkkk[y]) kkkk[y]=z;
43         else ++ans,kkkk[y]=std::min(kkkk[y],z);
44     }
45     For(i,1,n) if(kkkk[i]) ins(1,i,kkkk[i]), ins(i,1,kkkk[i]);
46 }
47 
48 void dij(){
49     memset(dis,0x3f,sizeof dis);
50     dis[1]=0; pq.push(P(0,1));
51     num[1]=1;
52     while(!pq.empty()){
53         P u=pq.top(); pq.pop();
54         if(u.first>dis[u.second]) continue;
55         for(int i=h[u.second];i;i=nxt[i]){
56             if(dis[u.second]+w[i]<dis[to[i]]){
57                 dis[to[i]]=dis[u.second]+w[i];
58                 pq.push(P(dis[to[i]],to[i]));
59                 num[to[i]]=num[u.second];
60             }
61             else if(dis[u.second]+w[i]==dis[to[i]])
62                 num[to[i]]+=num[u.second];
63         }
64     }
65 }
66 
67 int main(){
68     File("road");
69     init();
70     dij();
71     For(i,1,n){
72         if(!kkkk[i]) continue;
73         if(kkkk[i]>dis[i]) ++ans;
74         if(kkkk[i]==dis[i]&&num[i]>1) ++ans;
75     }
76     printf("%d",ans);
77     return 0;
78 }
相關文章
相關標籤/搜索