JZOJ 1981. 【2011集训队出题】Digit

JZOJ 1981. 【2011集训队出题】Digit

Time Limits: 1000 ms Memory Limits: 128000 KB

Description  

在数学课上,小T又被老师发现上课睡觉了。为了向全班同学证明小T刚才没有好好听课,数学老师决定出一道题目刁难一下小T,如果小T答不出,那么……

  情节就按照俗套的路线发展下去了,小T显然无法解决这么复杂的问题,可怜的小T只能向你求助:
  题目是这样的:
  求一个满足条件的n位数A(不能有前导0),满足它的数字和为s1,并且,A*d的数字和为s2.

Input

一行四个整数:n, s1, s2, d

Output  

若存在最小的满足条件的数,则输出这个数,否则输出-1。

Sample Input

2 9 9 5

Sample Output

18

Data Constraint

Hint

【样例说明】
  1+8=9
  185=90
  9+0=9
【数据范围】
  对于20%的数据满足n≤5。
  对于50%的数据满足n≤40
  对于100%的数据满足1≤n≤100,0≤s1≤n
9,0≤s2≤(n+1)*9,0≤d≤9

Solution

很容易就想到一个4维的状态: \(f[i,j,k,p]\)表示做到第i位,原数位和为j,乘d之后的数位和为k,并且乘d之后向前进位为p,是从哪一个转移过来的,显然f数组记录的数据不足。

所以,就将一维i放进f里面。所以状态就变成了3维。(i不足的可以用0补齐所以只用保留长度最短的)

先枚举答案的第一位是什么,还要再枚举p进位是多少。
这个答案的长度可能不一定为n,然后补0(不影响进位),越靠前越优。

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,x) for(int i=head[x];i;i=e[i].next)
#define mem(a,x) memset(a,x,sizeof(a))
#define mec(a,x) memcpy(a,x,sizeof(a))
typedef long long LL;
typedef double DB;
using namespace std;
template <typename T> inline T read(T &a) {
    T x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();a=f*x;
}
using namespace std;
const int N=1000,inf=0x3f3f3f3f;
int n,s1,s2,d,_x,_y,_z;
int f[N][N][10],g[N][N][10],W[N],Q[N];
int x,y,z,ans,now,pos;
bool cmp(int x1,int y1,int z1,int x2,int y2,int z2) {
    if((x1||x2||y1||y2||z1||z2)==0) return 0;
    if(g[x1][y1][z1]/10<g[x2][y2][z2]/10) return 1;
    if(g[x1][y1][z1]/10>g[x2][y2][z2]/10) return 0;
    now=g[x1][y1][z1]/10,z1=g[x1][y1][z1]%10,x1=x1-now,y1=y1-(now*d+z1)%10;
    now=g[x2][y2][z2]/10,z2=g[x2][y2][z2]%10,x2=x2-now,y2=y2-(now*d+z2)%10;
    return cmp(x1,y1,z1,x2,y2,z2);
}
bool cmp1(int* a,int* b) {
    fo(i,0,max(a[0],b[0])) {
        if(a[i]<b[i]) return 1;
        if(a[i]>b[i]) return 0;
    }
    return 0;
}
void getans(int x,int y,int z,int last,int* ans) {
    int len=n-f[x][y][z]-1;
    mem(ans,0),ans[ans[0]=1]=last;
    while(x||y||z) {
        if(g[x][y][z]/10*d/10+last*d%10<10) while(len)len--,ans[++ans[0]]=0;
        ans[++ans[0]]=g[x][y][z]/10;
        last=g[x][y][z]/10;
        now=g[x][y][z]/10,z=g[x][y][z]%10,x=x-now,y=y-(now*d+z)%10;
    }
    while(len)len--,ans[++ans[0]]=0;
}
int main() {
    freopen("1.in","r",stdin);
    read(n),read(s1),read(s2),read(d);
    mem(f,inf),mem(W,inf),ans=inf;
    f[0][0][0]=0;
    fo(i,0,s1) fo(j,0,s2) fo(k,0,9) if(f[i][j][k]<=n) {
        fo(now,0,9) {
            int x=i+now,y=j+(now*d+k)%10,z=(now*d+k)/10;
            if(f[i][j][k]+1<f[x][y][z]) f[x][y][z]=f[i][j][k]+1,g[x][y][z]=now*10+k;
            else if(f[i][j][k]+1==f[x][y][z]) {
                if(now<g[x][y][z]/10) g[x][y][z]=now*10+k;
                else if(now==g[x][y][z]/10) {
                    _z=g[x][y][z]%10,_x=x-g[x][y][z]/10,_y=y-((g[x][y][z]/10)*d+_z)%10;
                    if(cmp(i,j,k,_x,_y,_z)) g[x][y][z]=now*10+k;
                }
            }
        }
    }
    fo(h,1,9) {
        x=s1-h,now=ans=inf;
        if(x<0) continue;
        fo(tz,0,9) {
            z=tz,y=s2-(h*d+z)%10-(h*d+z)/10;
            if(y<0) continue;
            if(f[x][y][z]<n) {
                getans(x,y,z,h,Q);
                if(cmp1(Q,W)) ans=0,pos=tz,mec(W,Q);
            }
        }
        if(ans<n) {fo(i,1,n) printf("%d",W[i]);break;}
    }
    if(ans>=n) printf("-1\n");
}

原文地址:https://www.cnblogs.com/patricksu/p/8207036.html

时间: 2024-10-30 04:09:31

JZOJ 1981. 【2011集训队出题】Digit的相关文章

【JZOJ1914】【2011集训队出题】最短路

题目大意 给你一个带权无向图,满足图上任意一条边最多属于一个环,有\(q\)个询问,求\(u,v\)之间的最短路. \(n,q\leq 10000\) Solution 首先用Tarjan建一棵以\(1\)为根的搜索树,找出每个环,记录环的总长,将环内每个点\(u\)连向环内\(dfs\)序最小的点\(v\),边权为\(u\)到\(v\)的最短路,然后把不在环上的边照旧连上,这样我们就得到了一棵树. 现在要求\(a\)到\(b\)的最短路,我们考虑倍增,若两个点在一条链上,它们的最短路就是树上的

【2010集训队出题】小Z的袜子

Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬. 你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子.当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己

jzoj 2867. 【集训队互测 2012】Contra

Description 偶然间,chnlich 发现了他小时候玩过的一个游戏"魂斗罗",于是决定怀旧.但是这是一个奇怪的魂斗罗 MOD. 有 N 个关卡,初始有 Q 条命. 每通过一个关卡,会得到 u 分和1条命,生命上限为 Q.其中 u=min(最近一次连续通过的关数,R). 若没有通过这个关卡,将会失去1条命,并进入下一个关卡. 当没有生命或没有未挑战过的关卡时,游戏结束,得到的分数为每关得到的分数的总和. 由于 chnlich 好久不玩这个游戏了,每条命通过每个关卡的概率均为p(

jzoj 2866. 【集训队互测 2012】Bomb

Description 给你\(n\)个点,坐标分别为\((xi,yi)\).从中取出三个点,使得其两两间曼哈顿距离和最大和最小,求最大值和最小值. 对于 100% 的数据, N<=100000 , 0<=Xi,Yi<=10^8 Solution 看完题目后感觉要分类讨论,思考1h后果断暴力O(n^3). 但是判断了一下n<=500才跑暴力,得了30分.(?10^9过4s?不判50分) 其实可以O(n^2)暴力的.(听说O(n^2)+优化 = 100) 对于第一个最大值,我们可以\

[JZOJ1904] 【2010集训队出题】拯救Protoss的故乡

题目 题目大意 给你一个树形的网络,每条边从父亲流向儿子.根节点为原点,叶子节点流向汇点,容量为无穷大. 可以给一些边扩大容量,最多总共扩大\(m\)容量.每条边的容量有上限. 求扩大容量后最大的最大流. 思考历程 隐隐约约地猜到正解跟树链剖分有什么关系,可是没有打,也没有时间打. 只能暴力DP来水分. 设\(h_{i,j}\)为\(i\)的父亲到\(i\)的最大流,扩大了\(j\)次容量.\(g_{i,j}\)为\(i\)到子树的最大流,扩大了\(j\)次容量.前者由后者和边的容量取最小值后得

【JZOJ1899】【2010集训队出题】剪枝

题目大意 给出一个有根树,\(1\)为根,若某个节点的儿子全是叶子,你可以将该节点的儿子全部剪掉,这样的操作可以进行多次.定义这棵树的价值为:将树上所有叶子按照\(dfs\)序排序后,所有叶子点权之和-相邻两叶子路径上点权最大值.现在你要通过剪枝使得这棵树价值最大. \(n\leq 100000\) 分析 设\(f_i\)表示\(i\)作为最后一个叶子时的最大价值.暴力枚举原树(没有剪枝)相邻的两个叶子,显然左链上每个点的\(f\)都可以转移到右链上,我们暴力处理出这条路径,分类讨论点权最大值在

[JZOJ1901] 【2010集训队出题】光棱坦克

题目 题目大意 给你个平面上的一堆点,问序列\({p_i}\)的个数. 满足\(y_{p_{i-1}}>y_{p_i}\)并且\(x_{p_i}\)在\(x_{p_i-1}\)和\(x_{p_i-2}\)之间. 正解 我不知道为什么我的树状数组打挂了--尽管不一定能AC,但是WA了-- 这题的正解有很多,最为传奇的,则是彭大爷的神仙解法. 显然这是个DP,而他抛弃了按照\(y\)从大到小排序的传统做法,反而是以\(x\)从小到大排序.将\({p_i}\)倒过来做.设\(f_{i,0/1}\)表示

圆方树小结

圆方树 jzoj 1914. [2011集训队出题]最短路 这是道圆方树+倍增LCA裸题. 圆方树,顾名思义,就是圆点和方点所组成的树. 而方点就是一个圆的根,一般都是\(dfs\)时第一个到这个圆的那个位置,然后另附一个点当做方点.然后圆所组成的点都连向方点. 而对于这种圆方边的边权,则为它到根的最近值. 从而将一个仙人掌转成了一棵树. 然后对于这棵树,我们就可以用倍增来求出两两点之间的最短路了. 注意的是,对于最后走到的位置,我们要看看它是从上面绕近还是直接从下面走更优!!! 就这样子了.

国家集训队2011 happiness

[试题来源] 2011中国国家集训队命题答辩 [问题描述] 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值.作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大. [输入格式] 第一行两个正整数n,m.接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学