codeforces - Cycles(思维)

好多事情,今晚要上安卓选修了,学多一技防身 = =

题目传送门

题意
第一行给一个k,表示你要构造一些点和他们之间的边,使得所组成的不同的三角形恰好为k个

第一行输出你选了n个点,下面输出n*n的邻接矩阵来表示点和边之间的联系,0位没有建边,1位有建边

注意 3 <= n <= 100,1 <= k <= 1e5

input
1
output
3
011
101
110

input
10
output
5
01111
10111
11011
11101
11110

思路
思路嘛。。当时写写画画没什么思路 = =

思路是先建立一个有n个点的完全图,就是每个点之间都有连边,说明这些点不能再连了。这个n个点形成的完全图有的三角形个数要>=k,说明n-1个点形成的完全图,再添加一些点连边,就能达到k,然后我们要找找添加点和边,产生的三角形的规律 = =

下表n表示n个点,m表示连m条边,sum表示有sum个不同的三角形

nmsum
331
43 + 2 = 51+1 = 2
45 + 1 = 62 + 2 = 4
56 + 2 = 84 + 1 = 5
58 + 1 = 95 + 2 = 7
68 + 2 = 105 + 1 = 6

可以看出在n-1个点的完全图上,添加第n个点,第一次要连2条边,sum增加1,第二次要连1条边,sum增加2,在写下去就发现第三次要连1条边,sum增加3

所以n个点的完全图,有(1)+(1+2)+(1+2+3)+…+(1+2+…+n-2)个不同的三角形,因为(1)+(1+2)+(1+2+3)+…+(1+2+…+n)= n*(n+1)*(n+2) / 6,
把 n+2 变成n,(1)+(1+2)+(1+2+3)+…+(1+2+…+n-2)= (n-2)*(n-1)*n / 6

最后还有一点,一个新开的点,连边之后,三角形增加的数量是+1,+2,+3… 倘若要增加边数为2,就要再新开一个点,新开的第一个点+1个三角形,新开的第二个点+1个三角形,就能达到2个,昨晚wa了一发 = =

代码

#include  <algorithm>//           ¨|¨|¨|        ¨|¨|¨|¨|
#include   <iostream>//         ¨}¨}¨}¨}      ¨~¨~¨~
#include    <cstring>//        ¨~¨~ ¨~¨~    ¨~¨~
#include    <stdio.h>//       ¨~¨~  ¨~¨~   ¨~¨~
#include     <vector>//      ¨~¨~   ¨~¨~  ¨~¨~
#include      <cmath>//     ¨~¨~    ¨~¨~  ¨~¨~
#include      <queue>//    ¨~¨~ ¨~¨~¨~¨~  ¨~¨~
#include        <map>//   ¨~¨~      ¨~¨~   ¨~¨~
using namespace std ;//  ¨~¨~       ¨~¨~    ¨~¨~¨~
typedef long long ll;// ¨~¨~        ¨~¨~      ¨~¨~¨~¨~¨~
#define pi pair<int,int>  ///
#define P(x,y) make_pair(x,y)
const int maxn = 1e5 + 5;
const ll mod = 998244353;
ll read()
{
	ll x=0;char ch=getchar(); bool flag = false;
	if(ch=='-') { flag = true; ch = getchar();}
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	if(flag) return -x;  else return x;
}

int ans[105][105];

int main()
{   if(fopen("in.txt","r")) freopen("in.txt","r",stdin);
    int T,n,m,k,i,sum,j,t,tmp,t2,k1,k2;
    scanf("%d",&k);
    for(i=3;i<=100;i++)
        if(i*(i-1)*(i-2)/6>=k){
            t = i-1;
            break;
        }
    tmp = k - t*(t-1)*(t-2)/6;
    // cout<<tmp<<endl;
    for(i=1;i<=t;i++)
        for(j=1;j<=t;j++)
            if(i!=j) ans[i][j] = 1;
    if(tmp==0){
        printf("%d\n",t);
        for(i=1;i<=t;i++){
            for(j=1;j<=t;j++) printf("%d",ans[i][j]);
            printf("\n");
        }
    }else{
        int cnt = 1;
        for(i=t+1;i<=100;i++){
            while(tmp>=cnt){
                if(cnt==1){
                    ans[1][i] = ans[2][i] = ans[i][1] = ans[i][2] = 1;
                }else{
                    for(j=3;j<=cnt+1;j++)
                        ans[j][i] = ans[i][j] = 1;
                }
                tmp -= cnt;
                cnt++;
            }
            if(tmp!=0&&tmp<cnt) cnt = 1;
            else break;
        }
        t = i;
        printf("%d\n",t);
        for(i=1;i<=t;i++){
            for(j=1;j<=t;j++) printf("%d",ans[i][j]);
            printf("\n");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值