hdu 5535 Cake 构造+记忆化搜索

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5355

题意:给定n与m,其中1<= n <= 1e5,2 <= m <= 10;问是否存在将1~n个数分成m组,使得每组的和相等;若存在输出m行,每行表示一组的值,否则输出NO;

ps:总共T<=1000组数据,还是挺大的;



思路:预判之后,若可能存在则直接以2m为周期,从大往小构造出和相等的m组,这样就可以将n的值缩小到2m~4m-2;因为当n = 4m-1时,再次减去一个周期,下一个讨论的右边界为2m-1,易知(2m-1)*2m/2/m是可以构造出符合的m个式子的;并且坑爹的是,出题人这次的常数系数不能太大,AC的代码运行了514ms,当把n 周期缩小处改为n > 4*m-1时,直接TLE了;在搜索中系数大了不止一倍;

dfs也是比较巧妙,需要加个start来单调查找每组的数据,是最终全部m组全部求完了再return true,并不是每组完成就直接return,这样还可以修改直接选择的错误;

判断一组完成了只是将参数值复原为原始值;还有需要使用dp优化,设置了define来简写;

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define rep0(i,l,r) for(int i = (l);i < (r);i++)
  4 #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
  5 #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
  6 #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
  7 #define MS0(a) memset(a,0,sizeof(a))
  8 #define MS1(a) memset(a,-1,sizeof(a))
  9 #define MSi(a) memset(a,0x3f,sizeof(a))
 10 #define inf 0x3f3f3f3f
 11 #define lson l, m, rt << 1
 12 #define rson m+1, r, rt << 1|1
 13 #define lowbit(x) (x&(-x))
 14 typedef pair<int,int> PII;
 15 #define A first
 16 #define B second
 17 #define MK make_pair
 18 typedef long long ll;
 19 typedef unsigned int uint;
 20 template<typename T>
 21 void read1(T &m)
 22 {
 23     T x=0,f=1;char ch=getchar();
 24     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 25     while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 26     m = x*f;
 27 }
 28 template<typename T>
 29 void read2(T &a,T &b){read1(a);read1(b);}
 30 template<typename T>
 31 void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
 32 template<typename T>
 33 void out(T a)
 34 {
 35     if(a>9) out(a/10);
 36     putchar(a%10+‘0‘);
 37 }
 38 int i,j,k,n,m,l,r;
 39 const int N = 1e5+7;
 40 int ans[11][N],aux[11][N],vs[44],ave,board;
 41 int dp[50][11],rec[50][11][11][50];
 42 #define def rec[board][m]
 43 bool dfs(int tot,int id,int start)
 44 {
 45     if(tot == ave){id++;tot = 0;start = 1;} // 这是一项结束了,是另一项的开始;当然了只有全部结束时,才返回true;
 46     if(id == m){
 47         rep1(i,1,board)if (!vs[i]){
 48             aux[id][++aux[id][0]] = i;
 49         }
 50         return true;
 51     }
 52     rep1(i,start,board){
 53         if(tot+i > ave) return false;
 54         if(!vs[i]){
 55             vs[i] = 1;
 56             aux[id][++aux[id][0]] = i;
 57             if(dfs(tot+i,id,i+1))  return true;
 58             vs[i] = 0,aux[id][0]--;
 59         }
 60     }
 61     return false;
 62 }
 63 bool solve(int top)
 64 {
 65     if(top >= 4*m-1){
 66         for(int i = 1,j = 0;i <= m;i++,j++){
 67             ans[i][++ans[i][0]] = top-2*m+1+j;
 68             ans[i][++ans[i][0]] = top-j;
 69         }
 70        return  solve(top-2*m);
 71     }
 72     else{
 73         ave = top*(top+1)/m/2;
 74         //printf("%d ",ave);
 75         board = top;
 76         if(dp[board][m] == 0){
 77             if(dfs(0,1,1)){
 78                 dp[board][m] = 1;
 79                 rep1(i,1,m)
 80                     rep1(j,0,aux[i][0])
 81                         def[i][j] = aux[i][j]; // define了
 82             }
 83             else dp[board][m] = -1;
 84         }
 85         if(dp[board][m] == 1) return true;
 86         return false;
 87     }
 88 }
 89 int main()
 90 {
 91     //freopen("data.txt","r",stdin);
 92     //freopen("out.txt","w",stdout);
 93     int T; read1(T);
 94     for(int kase = 1;kase <= T;kase++){
 95         MS0(vs);
 96         rep1(i,0,10) ans[i][0] = aux[i][0] = 0;
 97         read2(n,m);
 98         ll sum = 1LL*n*(n+1)/2;
 99         if(sum%m || sum/m < n || !solve(n)){
100             puts("NO");
101             continue;
102         }
103         puts("YES");
104         rep1(i,1,m){
105             printf("%d",ans[i][0]+def[i][0]);
106             rep1(j,1,ans[i][0])
107                 printf(" %d",ans[i][j]);
108             rep1(j,1,def[i][0])
109                 printf(" %d",def[i][j]);
110             puts("");
111         }
112     }
113     return 0;
114 }
时间: 2024-12-09 21:10:45

hdu 5535 Cake 构造+记忆化搜索的相关文章

hdu 2833 WuKong(最短路径+记忆化搜索)

http://acm.hdu.edu.cn/showproblem.php?pid=2833 大致题意:给定一个无向图,以及悟空和师傅起点与终点,求它们分别从起点到终点的最短路径中经过相同的点的最大个数. 思路:首先dijkstra求出最短路,那么如果有dis[a] + map[a][b] = dis[b],则边(a,b)一定在最短路径上.根据这一定理可以求出所有最短路径.然后类似于求最长公共子序列求经过的相同点的最大个数. 即若a==b ,dp[a][b] = max(dp[i][j]+1)

HDU 4597 Play Game(记忆化搜索,深搜)

题目 //传说中的记忆化搜索,好吧,就是用深搜//多做题吧,,这个解法是搜来的,蛮好理解的 //题目大意:给出两堆牌,只能从最上和最下取,然后两个人轮流取,都按照自己最优的策略,//问说第一个人对多的分值.//解题思路:记忆化搜索,状态出来就非常水,dp[fl][fr][sl][sr][flag],//表示第一堆牌上边取到fl,下面取到fr,同样sl,sr为第二堆牌,flag为第几个人在取.//如果是第一个人,dp既要尽量大,如果是第二个人,那么肯定尽量小. http://www.2cto.co

UVa 1629 Cake slicing (记忆化搜索)

题意:一个矩形蛋糕上有好多个樱桃,现在要做的就是切割最少的距离,切出矩形形状的小蛋糕,让每个蛋糕上都有一个樱桃,问最少切割距离是多少. 析:很容易知道是记忆化搜索,我们用dp[u][d][l][r]来表示,上界是u,下界是d,左边是l,右边是r,然后不断切割,不过要注意切的时候是按缝隙切, 缝隙多一条,那么我们可以补上一条,用0来补齐,然后就进行计算就好. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #in

hdu 4597 Play Game(记忆化搜索)

题目链接:hdu 4597 Play Game 题目大意:给出两堆牌,仅仅能从最上和最下取,然后两个人轮流取,都依照自己最优的策略.问说第一个人对多的分值. 解题思路:记忆化搜索,状态出来就很水,dp[fl][fr][sl][sr][flag],表示第一堆牌上边取到fl,以下取到fr,相同sl.sr为第二堆牌,flag为第几个人在取.假设是第一个人,dp既要尽量大,假设是第二个人,那么肯定尽量小. #include <cstdio> #include <cstring> #incl

HDU 3779 Railroad(记忆化搜索)

Railroad Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 10   Accepted Submission(s) : 3 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description A train yard is a complex ser

hdu 5787 数位dp,记忆化搜索

题意:求区间[l,r]内有多少个数符合,这个数的任意的相邻k位数(digits),这k个数都两两不相等 l,r范围是1~1e18,k是2~5 思路:数位DP,因为K<=5,我们最多需要保存下来当前位的前4位就足够了.因为dp[pos][p1][p2][p3][p4]表示,现在枚举取第pos位,pos位之前的四位分别为p1,p2,p3,p4,p4是pos的上一位.那么p1~p4的范围就是0~9,但是因为总位数小于当前数字的位数的数也要进行枚举,需要一个数字来区分它是前导0还是在中间时为0,令p =

HDU 1428-漫步校园(记忆化搜索)

漫步校园 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3071    Accepted Submission(s): 932 Problem Description LL最近沉迷于AC不能自拔,每天寝室.机房两点一线.由于长时间坐在电脑边,缺乏运动.他决定充分利用每次从寝室到机房的时间,在校园里散散步.整个HDU校园呈方形布局,可划

HDU 5115 Dire Wolf(记忆化搜索)

题目大意:有n只狼,每只狼有一个自己攻击的属性,还有一个属性就是可以给左边和右边的狼提高攻击力.这个左边的意思是如果离得最近的那个死了,攻击力加给离得左边没死的最近的一个. 思路:一开始以为贪心可解,但是显然想简单了啊.后来知道了是区间dp,dp[i][j]代表在区间i到j内的最小伤害数.关键是划分区间,我们让设k为区间内最后死的那匹狼,那么区间内就有状态转移公式:dp[i][j] = min(dp[i][j],    dp[i][k-1]+dp[k+1][j]+ num[k] + f[i-1]

HDU 1978-How many ways(记忆化搜索)

How many ways Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3105    Accepted Submission(s): 1823 Problem Description 这是一个简单的生存游戏,你控制一个机器人从一个棋盘的起始点(1,1)走到棋盘的终点(n,m).游戏的规则描述如下: 1.机器人一开始在棋盘的起始点并