HDU 5355 Cake

HDU 5355 Cake


更新后的代码:

今天重新做这道题的时候想了很多种思路

最后终于想出了自认为完美的思路,结果却超时

真的是感觉自己没救了

最后加了记忆化搜索,AC了

好了先说下思路吧,不知道大家住没注意m<=10

我们可以把大部分的数据写成成对的形式例如n=27 m=6的这组数据

第1份  27  16

第2份  26  17

第3份  25  18

第4份  24  19

第5份  23  20

第6份  22  21

剩下1~15搜索出6等份分给所有人

这样成对出现的数蛇形数我们去处尽量多的偶数条

保证剩下的数的个数大于等于2*m小于4*m个

所以剩下的小于4m(小于40)个数我们只解用搜索就好了

所以n 的范围就变成1~40,m的范围1~10这样我们记录这些的结果(防止这样的数据大量重复出现)

这样如果我们有数据15 6计算过后

n=27  m= 6

n=39  m=6

n=15+(任意被的12) m=6

我们都不需要搜索了

就这样这个问题就解决了


#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define maxn 100005
#define ll __int64
#define cnm c[nu][m]
using namespace std;
int v[15][maxn];
ll m,n;
//fun函数定义将1-num平均分给l-r个人
int a[15][50];
int si[15];
bool b[50];
int dp[50][10]={0};
int c[50][10][15][50]={0};
ll ave,nu;
bool dfs(int sum,int g,int s){
    if(sum==ave){g++;sum=0;s=1;}
    if(g==m-1){
        for(int i=1;i<=nu;i++)
            if(!b[i])a[g][++a[g][0]]=i;
        return true;
    }
    for(int i=s;i<=nu;i++){
        if(sum+i>ave) return false;
        if(!b[i]){
            b[i]=true;
            a[g][++a[g][0]]=i;
            if(dfs(sum+i,g,i+1)) return true;
            b[i]=false;
            a[g][0]--;
        }
    }
    return false;
}

bool fun(ll num){
    if(num>=4*m-1){
        for(int i=0,j=0;i<m;i++,j++){
            v[i][si[i]++]=num-j;
            v[i][si[i]++]=num-2*m+1+j;
        }
        return fun(num-2*m);
    }
    else {
        nu=num;
        ave=(num+1)*num/2/m;
        int b;
        if(dp[num][m]==0){
            if(dfs(0,0,1)){
                dp[num][m]=1;
                for(int i=0;i<m;i++)
                    for(int j=0;j<=a[i][0];j++)
                        cnm[i][j]=a[i][j];
            }
            else dp[num][m]=-1;
        }
        if(dp[nu][m]==1) return true;
        return false;
    }
}
void out(int n){
    printf("YES\n");
    for(int i=0;i<n;i++){
        printf("%d",si[i]+cnm[i][0]);
        for(int j=0;j<si[i];j++) printf(" %d",v[i][j]);
        for(int j=0;j<cnm[i][0];j++) printf(" %d",cnm[i][j+1]);
        printf("\n");
    }
}
void Init(){
    memset(si,0,sizeof(si));
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%I64d%I64d",&n,&m);
        ll su=n*(n+1)/2;
        ll av=su/m;
        if(su%m||av<n)printf("NO\n");
        else{
            Init();
            bool ok=fun(n);
            if(ok)out(m);
            else printf("NO\n");
        }
    }
    return 0;
}

 




/*

此代码存在局限性数据更新后已不能在AC

待更新……

*/

这个题目看上去的时候第一感觉就是暴力,结果真的一遍就过了


#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define maxn 100005
#define ll __int64
using namespace std;
int a[maxn];
vector <int > v[maxn];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        ll n,m;
        scanf("%I64d%I64d",&n,&m);
        ll sum =(n+1)*n/2;
        if(sum%m==0){
            ll ave=sum/m;
            if(ave<n)
                printf("NO\n");
            else{
                memset(v,0,sizeof(v));
                memset(a,0,sizeof(a));
                int t=ave,A=0;
                int flag=0;
                for(int i=n;!flag&&i>=1;i--){
                    if(a[i]==0){
                        t-=i;
                        v[A].push_back(i);
                        a[i]=1;
                    }
                    if(i-1>t){
                        for(int j=i-1;t&&j>=1;j--){
                            if(t>=j&&a[j]==0){
                                v[A].push_back(j);
                                t-=j;
                                a[j]=1;
                            }
                        }
                    }
                    if(t==0){
                        t=ave;
                        A++;
                    }
                }
                if(A==m){
                    printf("YES\n");
                    for(int i=0;i<m;i++){
                        printf("%d",v[i].size());
                        for(int j=0;j<v[i].size();j++)
                            printf(" %d",v[i][j]);
                        printf("\n");
                    }
                }
                else
                    printf("NO\n");
            }
        }
        else
            printf("NO\n");
    }
    return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值