D - Degree Set CodeForces - 976D 双指针

 Degree Set
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given a sequence of n positive integers d1, d2, ..., dn (d1 < d2 < ... < dn). Your task is to construct an undirected graph such that:

  • there are exactly dn + 1 vertices;
  • there are no self-loops;
  • there are no multiple edges;
  • there are no more than 106 edges;
  • its degree set is equal to d.

Vertices should be numbered 1 through (dn + 1).

Degree sequence is an array a with length equal to the number of vertices in a graph such that ai is the number of vertices adjacent toi-th vertex.

Degree set is a sorted in increasing order sequence of all distinct values from the degree sequence.

It is guaranteed that there exists such a graph that all the conditions hold, and it contains no more than 106 edges.

Print the resulting graph.

Input

The first line contains one integer n (1 ≤ n ≤ 300) — the size of the degree set.

The second line contains n integers d1, d2, ..., dn (1 ≤ di ≤ 1000, d1 < d2 < ... < dn) — the degree set.

Output

In the first line print one integer m (1 ≤ m ≤ 106) — the number of edges in the resulting graph. It is guaranteed that there exists such a graph that all the conditions hold and it contains no more than 106 edges.

Each of the next m lines should contain two integers vi and ui (1 ≤ vi, ui ≤ dn + 1) — the description of the i-th edge.

Examples
input
Copy
3
2 3 4
output
Copy
8
3 1
4 2
4 5
2 5
5 1
3 2
2 1
5 3
input
Copy
3
1 2 3
output
Copy
4
1 2
1 3
1 4
2 3

 

题意:给出无向图所有节点的度组成的集合(集合默认从大到小并且不重复),且无向图中无重边自环,节点数为最高度+1。询问一种构造方式能构造出一个符合上述度集以及要求的图,输出所有的边。保证一定有这样的图存在。
 
题解:保证存在那就直接莽,别慌。设总节点数为 dn+1dn+1。设我们从度集左右两边以及按照编号大小两边同时构造这个图。首先r为当前和其他点连边的结点点,l为r所可以连接到的编号最低的结点,即每次我们都将r与[l,r-1]连边。那么我们的r结点连完以后有dn+2ldn+2−l的度(r右侧的结点都是有跟r连边的)。按编号两边构造的意思是我们每次构造出指定要求的度数点后l要增加,r要减少。设rt为度集最右侧的还未出现过的度数下标drtdrt即为该度数,lt为度集最左侧的还未出现过的度数下标dltdlt即为该度数。那我们每次构造就要构造出一对drtdltdrt和dlt 然后lt++,rt--。
    对 dltdlt构造,那么我们需要dn+1到 dn+1dlt 号r侧的点实行上述的连边操作,那么l的结点的度就会达到要求的dltdlt。那么假如现在 l 的度数为 degreel ,那么我们只需要 [rdltdegreel+1,r][r−dlt−degreel+1,r] 这些点实行上述的连边操作,那么[l,rdltdegreel][l,r−dlt−degreel] 的结点度数都会变为dltdlt ,然后把r更新为rdltdegreelr−dlt−degreel。因此不难看出其实原来的 degreeldegreel 是 dlt1dlt−1。然后就是 drtdrt 的构造了。上面我们说每个r连到 l 有 dn+2ldn+2−l的度,因此我们每次构造 dltdlt前,把 l 增加到(更新为)dn+1drtdn+1−drt ,那么就能保证上述连边的这些r他们的度数为drtdrt。这样不断操作直到rt<ltrt<lt 就能构造出符合要求的图。
 
#include<bits/stdc++.h>
 #define clr(x) memset(x,0,sizeof(x))
 #define mod 1000000007
 #define clr_1(x) memset(x,-1,sizeof(x))
 #define INF 0x3f3f3f3f
 #define LL long long
 #define pb push_back
 #define pbk pop_back
 using namespace std;
 const int N=3e3+10;
 int a[N];
 vector<int> dt[N];
 int rt,n,p,lt,r,l,ans;
 int main()
 {
     scanf("%d",&n);
     for(int i=1;i<=n;i++)
         scanf("%d",a+i);
     for(int i=1;i<=a[n]+1;i++)
         dt[i].clear();
     rt=n;
     r=a[n]+1;
     lt=1;
     l=1;
     while(lt<=rt)
     {
         while(dt[l].size()<a[lt])
         {
           for(int j=l;j<r;j++)
                 dt[j].pb(r);
             r--;
         }
         rt--;
         lt++;
         l=a[n]+1-a[rt];
     }
     ans=0;
     for(int i=1;i<=a[n]+1;i++)
         ans+=dt[i].size();
     printf("%d\n",ans);
     for(int u=1;u<=a[n]+1;u++)
     {
         for(auto v:dt[u])
             printf("%d %d\n",u,v);
     }
     return 0;
}

 

//双指针
/* LittleFall : Hello! */
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read();
inline void write(int x);
const int M = 1024;
int save[M];

int main(void)
{
    int n=read(),ans=0;
    for(int i=1;i<=n;i++)
        save[i]=read();
    int vecs=save[n]+1;

    int r=n,l=1,ready=0;
    for(int vec=1;vec<vecs;vec++)
    {
        if(save[l]<=ready)
            l++,r--;    
        else if(ready+vecs-vec==save[r])
            ready++,ans+=vecs-vec;
    }
    printf("%d\n",ans );

    r=n,l=1,ready=0;
    for(int vec=1;vec<vecs;vec++)
    {
        if(save[l]<=ready)
            l++,r--;
        else if(ready+vecs-vec==save[r])
        {
            for(int j=vec+1;j<=vecs;j++)
                printf("%d %d\n",vec,j );
            ready++;
            ans+=vecs-vec;
        }
    }

    return 0;
}


inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}

 

转载于:https://www.cnblogs.com/upstart/p/8982436.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值