1. 程式人生 > >11.3 AHSOFNU 校內模擬

11.3 AHSOFNU 校內模擬

long make closed set 輸出 上一條 edge end 當前

塊(block

【問題描述】
  拼圖達人小 C 手裏有 n 個 1*1 的正方形方塊,他希望把這些方塊拼在一起, 使得拼出的圖形周長最小, 要求方塊不能重疊。 擅長拼圖的小 C 一下就求出了這個周長, 順便他想考考你會不會求。
【輸入格式】
  多組數據, 第一行一個正整數 T, 表示數據組數。
  接下來 T 行, 每行一個正整數 n, 表示方塊數。
【輸出格式】
  輸出 T 行, 每行一個正整數, 表示答案。

【樣例輸入】
  3
  4
  11
  22
【樣例輸出】
  8
  14
  20


【數據範圍】
  對於 20%的數據, n<=20
  對於 40%的數據, n<=1000
  對於 60%的數據, n<=10^6

  對於 80%的數據, n<=10^10
  對於 100%的數據, n<=10^12T<=10

Solution:

  數學題。首先正方形一定是周長最小的,由此可以對 n 進行開方,然後把剩下的小方塊圍在正方形邊上即可。

Code:

 1 #include<cstdio>
 2 #define MAXN 1000000
 3 #define ll long long
 4 #define debug 0
 5 using namespace std;
 6 int t,ans=0;
 7 inline int Sqrt(ll x){
 8     ll l=0
,r=MAXN; 9 while(l<=r){ 10 ll mid=(l+r)>>1; 11 if(mid*mid<=x&&(mid+1)*(mid+1)>x) return mid; 12 if (mid*mid<x) l=mid+1; 13 else r=mid-1; 14 } 15 } 16 int main(){ 17 freopen("block.in","r",stdin); 18 freopen("block.out
","w",stdout); 19 scanf("%d",&t); 20 for(int i=1;i<=t;i++){ 21 ll n;scanf("%lld",&n); 22 int len=Sqrt(n); 23 #if debug 24 printf("len=%d\n",len); 25 #endif 26 ans=4*len; 27 n-=1ll*len*len; 28 if(n<=len&&n>=1) ans+=2; 29 else if(n>len) ans+=4; 30 printf("%d\n",ans); 31 } 32 return 0; 33 }

樹(tree)

【問題描述】
  今天 F 大爺看到了一張 n 個點的無向完全圖, 每條邊有邊權。 F大爺一開心就花 0.03 飛秒(即3*10-17 秒) 求了一下這張圖的最小生成樹以及最小生成樹的個數。 F 大爺驚喜地發現這張圖只有一個最小生成樹, 他現在更開心了, 於是他把這個最小生成樹告訴了你, 要你求出原來的完全圖中邊權和最小是多少。
【輸入格式】
  多組數據, 第一行一個正整數 T, 表示數據組數。
  每組數據的第一行一個正整數 n, 表示點數。
  接下來 n-1 行, 每行三個正整數 xi,yi,wi, 表示最小生成樹上 xi和 yi 之間有一條權值為 wi 的邊。
【輸出格式】
  輸出 T 行, 每行一個整數, 表示答案。

【樣例輸入】
  2
  3
  1 2 4
  2 3 7
  4
  1 2 1
  1 3 1
  1 4 2
【樣例輸出】
  19
  12


【數據範圍】
對於 20%的數據, T,n,wi<=5;
對於另外 30%的數據, n<=1000, 給的樹是一條鏈;
對於 100%的數據, T<=10, n<=20000, wi<=10000。

Solution:

  並查集。

  考慮kruskal,每次連上一條邊,兩個端點所在的聯通塊之間連的邊除了我們要加入的邊,其他邊都必須大於這條邊,帶權並查集維護即可。

Code:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define MAXN 20005
 4 #define ll long long
 5 #ifdef WIN32
 6 #define LL "%I64d"
 7 #else
 8 #define LL "%lld"
 9 #endif
10 using namespace std;
11 int t,n;
12 ll ans=0;
13 struct edge{
14     int u,v,val;
15 }e[MAXN];
16 int fa[MAXN],val[MAXN],size[MAXN];
17 inline int cmp(edge a,edge b){return a.val<b.val;}
18 inline int find(int x){
19     if(fa[x]==x) return x;
20     return fa[x]=find(fa[x]); 
21 } 
22 inline int merge(int x,int y,int val){
23     int fx=find(x),fy=find(y);
24     ans+=1LL*size[fx]*size[fy]*(val+1)-1;
25     fa[fx]=fy;size[fy]+=size[fx];
26 }
27 int main(){
28     freopen("tree.in","r",stdin);
29     freopen("tree.out","w",stdout);
30     scanf("%d",&t);
31     for(int i=1;i<=t;i++){
32         ans=0;
33         scanf("%d",&n);
34         for(int i=1;i<=n;i++) fa[i]=i,size[i]=1;
35         for(int j=1;j<=n-1;j++){
36             scanf("%d%d%d",&e[j].u,&e[j].v,&e[j].val);
37         }
38         sort(e+1,e+n,cmp);
39         for(int j=1;j<=n-1;j++){
40             merge(e[j].u,e[j].v,e[j].val);
41         }
42         printf(LL"\n",ans);
43     }
44 }

球(ball)

【問題描述】
  有 n 個不同顏色的球排成一排, 其中 n 為偶數。 小 D 打算把這些球按照某種玄妙的順序放入一個球筒中。每次他會選擇一個不是當前第一個的球, 先把這個球放入球筒, 接著把這個球的前一個也放入球筒, 重復這個操作直到所有球都進入球筒。 小 D 希望最後球筒中從頂到底的顏色序列字典序最小, 但他不會做, 所以請你幫幫他。
【輸入格式】
  第一行一個正整數 n, 表示球的個數。
  第二行 n 個正整數 ai, 分別表示每個球的顏色。
【輸出格式】
  輸出一行 n 個正整數, 表示球筒字典序最小的顏色序列。
【樣例輸入 1】
  4
  3 2 4 1
【樣例輸出 1】
  3 1 2 4
【樣例輸入 2】
  8
  4 6 3 2 8 5 7 1
【樣例輸出 2】
  3 1 2 7 4 6 8 5
【數據範圍】
  對於 30%的數據, n<=10;
  對於 60%的數據, n<=1000;
  對於 100%的數據, n<=200000, 1<=ai<=n, ai 互不相同。

Solution:

  60分做法:直接暴力。

  100分做法:倒著考慮取的順序,每次相當於把當前區間分成三段,每段長度都為偶數,支持分奇偶RMQ即可,再用堆維護這些區間,就能AC。(並不會...)

技術分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #define MAXN 200005
 4 #define INF 0x7fffffff
 5 using namespace std;
 6 int n,ans=0;
 7 int a[MAXN],vis[MAXN];
 8 bool flag;
 9 int main(){
10     freopen("ball.in","r",stdin);
11     freopen("ball.out","w",stdout);
12     memset(vis,0,sizeof(vis));
13     scanf("%d",&n);a[0]=INF;
14     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
15     for(int i=1;i<=n/2;i++){
16         int cnt1=0,cnt2=0;flag=0;
17         for(int j=1;j<=n;j++){
18             if(vis[j]==0){
19                 flag=flag?0:1;if(a[j]<a[cnt1]&&flag) cnt1=j;
20             }
21         }
22         vis[cnt1]=1;flag=0;
23         for(int j=cnt1+1;j<=n;j++){
24             if(vis[j]==0){
25                 flag=flag?0:1;if(a[j]<a[cnt2]&&flag) cnt2=j;
26             }
27             else break;
28         }
29         vis[cnt2]=1;flag=0;
30         printf("%d %d ",a[cnt1],a[cnt2]);
31     }
32 }
60分 技術分享
 1 #include<cstdio>
 2 #include<queue>
 3 using namespace std;
 4 #define N 262144
 5 #define INF 0x3FFFFFFF
 6 #define mp make_pair
 7 #define tp pq.top()
 8 #define F first
 9 #define S second
10 int t1[N*2+5],t2[N*2+5],p[N];
11 priority_queue<pair<pair<int,int>,pair<int,int> > > pq;
12 void build(int*t){for(int i=N;--i;)t[i]=min(t[i<<1],t[i<<1|1]);}
13 int query(int*t,int l,int r)
14 {
15     int res=INF;
16     for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
17     {
18         if(~l&1)res=min(res,t[l+1]);
19         if( r&1)res=min(res,t[r-1]);
20     }
21     return res;
22 }
23 void push(int l,int r)
24 {
25     if(l>r)return;
26     int x=query(l&1?t1:t2,l,r);
27     pq.push(mp(mp(-x,query(l&1?t2:t1,p[x]+1,r)),mp(l,r)));
28 }
29 int main()
30 {
31     freopen("ball.in","r",stdin);
32     freopen("ball.out","w",stdout);
33     int n,i,x,y,l,r;
34     scanf("%d",&n);
35     for(i=1;i<=n;++i)scanf("%d",&x),p[x]=i,t1[i+N]=i&1?x:INF,t2[i+N]=i&1?INF:x;
36     build(t1);build(t2);
37     for(push(1,n);!pq.empty();)
38     {
39         x=-tp.F.F;y=tp.F.S;l=tp.S.F;r=tp.S.S;
40         printf("%d %d ",x,y);pq.pop();
41         push(l,p[x]-1);push(p[x]+1,p[y]-1);push(p[y]+1,r);
42     }
43     fclose(stdin);fclose(stdout);return 0;
44 }
std

11.3 AHSOFNU 校內模擬