1 条题解

  • 0
    @ 2025-8-24 22:22:15

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Imakf
    **

    搬运于2025-08-24 22:22:15,当前版本为作者最后更新于2020-05-19 18:52:46,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    似乎被一些不太正常的做法艹了,所以赛后加了组 HACK 数据

    先讲不正经的部分分。

    testdata 1(4pts)\rm{testdata}\ 1(4pts) ai=0a_i=0

    答案全为 -1

    testdata 89(8pts)\rm{testdata}\ 8\sim9(8pts) p=2p=2

    因为 p=2p=2,所以只能把 44 放最后,前面直接贪心。

    testdata 1718(8pts)\rm{testdata}\ 17\sim18(8pts) ai=n\sum a_i=n

    然而出题人并不会这一档。

    testdata 1920(8pts)\rm{testdata}\ 19\sim20(8pts) ai=na_i=n

    发现非常容易搜出结果,直接爆搜。


    算法一:

    从高位到低位贪心搜索。

    期望得分:3232

    实际得分:??(取决于出题人心情)

    算法二:

    容易发现上述搜索算法在无解时一定会 TLE。

    于是限制每一组数据只能跑 200ms,超过则判 -1

    期望得分:4444

    实际得分:??(取决于出题人心情)


    算法三:

    容易发现,这是一道 dp 题。

    下面介绍一种错误的状态设计:

    dpb1,b4,b5,l,qdp_{b_1,b_4,b_5,l,q} 表示考虑了由高到低 ll 位,剩余 b1,b4,b5b_1,b_4,b_5a1,a4,a5a_1,a_4,a_5,当前模意义下为 qq 的最大答案(一个高精度数)。

    经过状态简化可以变为 dpb1,b4,b5dp_{b_1,b_4,b_5},含义不变。

    这么设计状态为什么错误?

    因为前面尽可能大,后面不一定能有解。

    就算从低位到高位考虑也是不对的,因为后面尽可能大前面不一定大。

    期望得分:??(取决于出题人心情)

    实际得分:N/A(出题人是懒狗,没写)。

    算法四:

    把原本的最优化 dp 转变为可行性 dp。

    dpb1,b4,b5,l,qdp_{b_1,b_4,b_5,l,q} 是否存在一个数,使得考虑了由低到高 ll 位,剩余 b1,b4,b5b_1,b_4,b_5a1,a4,a5a_1,a_4,a_5,当前模意义下为 qq

    容易发现这样 dp 求解,过程是 O(n4p)O(n^4p)

    考虑如何获得答案,固定 l=n,q=0l=n,q=0,枚举 b1,b4,b5b_1,b_4,b_5,贪心选取 5,4,15,4,1,获得答案。

    计算答案是 O(n3p)O(n^3p)

    总复杂度 O(Tn4p)O(Tn^4p)

    根据实现优劣可以拿到不同的分数。

    期望得分:202820\sim 28

    实际得分:N/A(出题人是懒狗,没写)。

    算法五:

    简化 dpdp 状态。

    将状态仅仅保留为 dpb1,b4,b5,qdp_{b_1,b_4,b_5,q}

    因为你可以通过 b1,b4,b5b_1,b_4,b_5 直接求得当前位数 ll

    总复杂度 O(Tn3p)O(Tn^3p)

    期望得分:5656

    算法六:

    继续简化 dpdp 状态。

    发现 pp 很小,可以直接使用 unsigned long long 进行压位。

    总复杂度 O(Tn3)O(Tn^3)

    期望得分:100100

    以下为 std。

    然而 std 的 dp 状态是 l,b1,b4l,b_1,b_4然而 std 的 dp 状态是 l,b1,b4l,b_1,b_4然而 std 的 dp 状态是 l,b1,b4l,b_1,b_4

    重要的事情说三遍。

    最后求答案时可以进行剪枝,跑得飞快。 std 未剪枝。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    
    using namespace std;
    #define ULL unsigned long long
    #define MX (234 + 1)
    #define pow10 IEE
    
    int n ,p;
    int a1 ,a4 ,a5 ,pow10[MX];
    ULL dp[MX][MX][MX];
    ULL LOOP(ULL x ,int bit){ // 循环左移
    	bit = (bit % p + p) % p; 
    	return (x << bit) | (x >> (p - bit));
    }
    
    struct BIGINT{
    	char k[MX];
    	int len;
    	BIGINT(){memset(k ,0 ,sizeof k); len = 0;}
    	void push_back(char c){k[len++] = c;} 
    	bool operator <(const BIGINT &B)const{
    		if(len != B.len) return len < B.len;
    		for(int i = 0 ; i < len ; ++i){
    			if(k[i] != B.k[i]) return k[i] < B.k[i];
    		}return false;
    	}
    	void output(){puts(k);}
    }Ans ,tmp;
    
    void solve(){
    	memset(dp ,0 ,sizeof dp); 
    	Ans = BIGINT(); 
    	cin >> n >> p >> a1 >> a4 >> a5;
    	pow10[0] = 1;
    	for(int i = 1 ; i <= n ; ++i){
    		pow10[i] = pow10[i - 1] * 10 % p;
    	}
    	dp[0][0][0] = 1;
    	for(int i = 0 ; i < n ; ++i){
    		for(int j = 0 ; j <= min(i ,a1) ; ++j){
    			for(int s = 0 ; s <= a4 && s + j <= i ; ++s){
    				int k = i - j - s; if(k > a5) continue;
    				dp[i + 1][j + 1][s] |= LOOP(dp[i][j][s] ,pow10[i] * 1 % p);
    				dp[i + 1][j][s + 1] |= LOOP(dp[i][j][s] ,pow10[i] * 4 % p);
    				dp[i + 1][j][s] |= LOOP(dp[i][j][s] ,pow10[i] * 5 % p);
    			}
    		}
    	}
    	for(int j = 0 ; j <= a1 ; ++j){
    		for(int s = 0 ; s <= a4 ; ++s){
    			int A5 = n - j - s ,A1 = j ,A4 = s;
    			if(A5 < 0 || A5 > a5 || (dp[n][j][s] & 1) == 0 ) continue;
    			ULL st = 1;
    			tmp = BIGINT();
    			for(int t = n ; t ; --t){
    				// priority: 5 > 4 > 1
    				if(A5 && (LOOP(st ,-pow10[t - 1] * 5) & dp[t - 1][A1][A4])){
    					tmp.push_back('5');
    					st = LOOP(st ,-pow10[t - 1] * 5) & dp[t - 1][A1][A4] ,--A5;
    				}else if(A4 && (LOOP(st ,-pow10[t - 1] * 4) & dp[t - 1][A1][A4 - 1])){
    					tmp.push_back('4');
    					st = LOOP(st ,-pow10[t - 1] * 4) & dp[t - 1][A1][--A4];
    				}else{
    					tmp.push_back('1');
    					st = LOOP(st ,-pow10[t - 1] * 1) & dp[t - 1][--A1][A4];
    				}
    			}
    			if(Ans < tmp) Ans = tmp;
    		}
    	}
    	if(Ans.len == 0) puts("-1");
    	else Ans.output();
    }
    
    int main(){
    	int T; cin >> T;
    	while(T--) solve();
    	return 0;
    }
    
    
    • 1

    信息

    ID
    5532
    时间
    1000ms
    内存
    128MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者