ICPC Camp 2016 几道神奇的构造打表题

SJTU Dreadnought Contest

The Magic Square

题意:已知 n100 , 你需要用n个边长为整数的正方形凑出一个大正方形,无解输出“Impossible”。
ps:如果加上边长互不相同就成神题了。
坑爹的note
考场送分题,几乎全对,关键是怎么实现比较好。

法1:考虑一个正方形,中间划十字多出3个,划九宫格多出8个,然后n大可以凑出来,小数据手推。

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <cstdlib>
#include <queue>
#include <stack>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
typedef long long ll;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
const int MAXN = 1000 +10;
int a[MAXN][MAXN]={0},l;
int a2[MAXN][MAXN]={0};
int n;

void draw(){
    For(i,l) {
        For(j,l) printf("%d ",a[i][j]);
        puts("");
    }
}
void tian8(int &l,int &x){
    For(i,3*l) For(j,3*l) {
        if (i>l || j>l) {
            int t=x+(i-1)/l+(j-1)/l*3;
            a[i][j]=t;
        }
    }
    l*=3; x+=8;
}
void tian3(int &l,int &x){
    For(i,2*l) For(j,2*l) {
        if (i>l || j>l) {
            int t=x+(i-1)/l+(j-1)/l*2;
            a[i][j]=t;
        }
    }
    l*=2; x+=3;
}
void kuo2(int &l){
    For(i,l){
        For(j,l) a2[i*2-1][j*2-1]=a2[i*2-1][j*2]=a2[i*2][j*2-1]=a2[i*2][j*2]=a[i][j];
    }
    l*=2;
    For(i,l){
        For(j,l) a[i][j]=a2[i][j];
    }
}
void plus3(int A,int B,int l,int &x) {
    Fork(i,A,A+l-1)
        Fork(j,B,B+l-1) {
            int t=x;
            if (i>=A+l/2) t+=1;
            if (j>=B+l/2) t+=2;
            if (t==x) continue;
            a[i][j]=t;
        }
    x+=3;
}
void plus8(int A,int B,int l,int &x) {
    Fork(i,A,A+l-1)
        Fork(j,B,B+l-1) {
            int t=x;
            if (i>=A+l/3) t+=(i-A)/3;
            if (j>=B+l/3) t+=(j-B)/3;
            if (t==x) continue;
            a[i][j]=t;
        }
    x+=8;
}
pair<pair<int,int> , int>  q[10000];
int head=1,tail=1;
void draw2() {
    Fork(i,head,tail) {
//      printf("%d,%d  %d\n",q[i].fi.fi,q[i].fi.se,q[i].se);
    }
}
void init() {
    q[1]=mp(mp(1,1),1);
}

void work(int X,int Y) {
    int p=1;
    int x=1;
    init();

    For(k,Y) {
        //draw2();
        tian8(l,x);
        pair<pair<int,int> , int> now=q[head];
        Rep(i,3) Rep(j,3)  {
            if (i||j)
            q[++tail] = mp(mp(now.fi.fi +i*p , now.fi.se+j*p ), p  );
        }
        p*=3;
    }


        kuo2(l);
        Fork(i,head,tail) q[i].fi.fi=q[i].fi.fi*2-1,q[i].fi.se=q[i].fi.se*2-1,q[i].se*=2;

//      kuo2(l);
//      Fork(i,head,tail) q[i].fi.fi=q[i].fi.fi*2-1,q[i].fi.se=q[i].fi.se*2-1,q[i].se*=2;


    For(k,X)
    {       
        while (q[head].se<2&&head<=tail) ++head;

        if (head>tail) {
            tian3(l,x);
            q[++tail]=mp(mp(1,l/2+1),l/2);
            q[++tail]=mp(mp(l/2+1,1),l/2);
            q[++tail]=mp(mp(l/2+1,l/2+1),l/2);
            if (++k>X) break;
            //draw();
        }

        plus3(q[head].fi.fi,q[head].fi.se,q[head].se,x); ++head;
    }

    cout<<l<<endl;
    draw();
//  draw2();    
}


int main() {

    l=1; a[1][1]=1; int x=1;

    while(cin>>n) {
        if (n==2||n==5||n==3) {
            puts("Impossible");
            return 0;
        }
        else {
            puts("Possible");           

            int l=16*9;
            int x,y;
             {
                RepD(x,n+1) {
                    if (n-1-3*x>=0 && (n-1-3*x)%8==0) {
                        y=(n-1-3*x)/8;
                //      cout<<n<<' '<<x<<' '<<y<<endl;
                        work(x,y);
                        return 0;
                    }
                }
            }

            if (n==6) {
                cout<<"3"<<endl;
                puts("1 1 2");
                puts("1 1 3");
                puts("6 5 4");
                return 0;   
            }
            if (n==8) {
                puts("4");
                puts("1 1 1 2");
                puts("1 1 1 8");
                puts("1 1 1 7");
                puts("3 4 5 6");
                return 0;   
            }
            if (n==11) {
                puts("8");
                puts("1 1 1 2 2 2 3 3");
                puts("1 1 1 2 2 2 3 3");
                puts("1 1 1 2 2 2 6 6");
                puts("4 4 4 5 5 5 6 6");
                puts("4 4 4 5 5 5 7 7");
                puts("4 4 4 5 5 5 7 7");
                puts("8 8 9 9 10 10 11 11");
                puts("8 8 9 9 10 10 11 11");
                return 0;   
            }
            if (n==14) {
                puts("9");
                puts("1 1 2 2 3 3 10 10 10");
                puts("1 1 2 2 3 3 10 10 10");
                puts("4 4 5 5 6 6 10 10 10");
                puts("4 4 5 5 6 6 11 11 11");
                puts("7 7 8 8 9 9 11 11 11");
                puts("7 7 8 8 9 9 11 11 11");
                puts("12 12 12 13 13 13 14 14 14");
                puts("12 12 12 13 13 13 14 14 14");
                puts("12 12 12 13 13 13 14 14 14");
                return 0;   
            }
            if (n==17) {
                puts("14");
                puts("1 1 1 1 1 1 2 2 2 2 2 2 5 5");
                puts("1 1 1 1 1 1 2 2 2 2 2 2 5 5");
                puts("1 1 1 1 1 1 2 2 2 2 2 2 7 7");
                puts("1 1 1 1 1 1 2 2 2 2 2 2 7 7");
                puts("1 1 1 1 1 1 2 2 2 2 2 2 9 9");
                puts("1 1 1 1 1 1 2 2 2 2 2 2 9 9");
                puts("3 3 3 3 3 3 4 4 4 4 4 4 11 11");
                puts("3 3 3 3 3 3 4 4 4 4 4 4 11 11");
                puts("3 3 3 3 3 3 4 4 4 4 4 4 13 13");
                puts("3 3 3 3 3 3 4 4 4 4 4 4 13 13");
                puts("3 3 3 3 3 3 4 4 4 4 4 4 15 15");
                puts("3 3 3 3 3 3 4 4 4 4 4 4 15 15");
                puts("6 6 8 8 10 10 12 12 14 14 16 16 17 17");
                puts("6 6 8 8 10 10 12 12 14 14 16 16 17 17");
                return 0;   
            }   
        }
    }
    return 0;
}

刚才那个做法太麻烦了,我们考虑3个初始状态,分别是
1,6(九宫格其中4个合并成1个),8(16宫格9个合并成一个),然后不停划十字,小数据手推


受6和8的影响,我们考虑2个正方形对角抵在一起,剩下全用1*1填的情况


这题可以胡乱构造出来真心。

The Kirakira Cycle

题意:已知 fn(x)=ni=1(xmodi) ,构成了一个x到 fn(x) 的映射,这定义了一张图,对于每个点x只有一条有向边从该点出发,指向 fn(x) ,那么请问图中最大环的长度,只有 n104 是已知的。

毫无规律,只好打表,问题是怎么打。
显然 fn(x)fn(x1)=nd<=nd|xd
而且最长环出现的数主要在 [3/20(1+2+...+n),3/10(1+2+...+n)]
于是根据这个对于n太大的情况打表,小数据暴力。
还有随机的作法:因为链很长,所以在那个区间找10个点当起点试试就行了。(没试过)

XOR Tree

一棵树n个节点,编号1..n,构造一颗树,使至少n+1对节点满足路径上节点编号的xor和为零。

小数据爆搜,大数据构造,
大致思路是构造太阳
举例:
[预留图片]

Moscow SU Trinity Contest

Green Day

题意:给定 k100 ,求k个树,这些树节点数相同,且任意2图不出现下列情况:
存在两点(u,v),两棵树中路径(u,v)都经过不为u,v的点c
求任意解

GreenDay

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <cstdlib>
#include <queue>
#include <stack>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (500000000000LL)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
typedef long long ll;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 

int main() {
    int k=read();
    cout<<2*k<<endl;
    For(i,k) {
        Fork(j,i+1,k) cout<<i<<' '<<j<<endl << i+k <<' '<< j+k <<endl;
        Fork(j,1,i-1) cout<<i+k<<' '<<j<<endl << i<<' '<<j+k<<endl;
        cout<<i<<' '<<i+k<<endl;

    }


    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值