11.3 AHSOFNU 校内模拟

块(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
posted @ 2017-11-03 19:10  drizzly  阅读(601)  评论(4编辑  收藏  举报