2021台北ICPC Largest Remainder (状压DP)

image

  • 要输出方案,很容易想到把方案放到dp值。 但这样我们dp需要记录余数,还要给数字排列
  • 看到D的范围范围会想到状压,让dp的一维表示D个数字的使用情况。这样就可以用状压来得到数字的排列。 比如: 状压的 1000 就是第一个数字放到最高位,0100 是第二个数字放到最高位。
  • 时间复杂度是 D * K * (1 << D), 需要稍微剪枝一下
#include<bits/stdc++.h>
//#include <bits/extc++.h>
using namespace std;
// using namespace __gnu_cxx;
// using namespace __gnu_pbds;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);  
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define li __int128_t
//#define int long long
const int N = 1e5 + 5;
const int M = 1e6 + 5;
const int mod = 1e9 + 7;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);
ll f[205][1 << 16];
int a[205];
int main () {
   IOS 
   memset(f, -1, sizeof f);
   f[0][0] = 0;
   int n, K; cin >> n >> K;
   for ( int i = 0; i < n; ++ i ) cin >> a[i];
   for ( int i = 0; i < 1 << n; ++ i ) {
       for ( int j = 0; j < K; ++ j ) {
           if(f[j][i] == -1) continue;
           for ( int k = 0; k < n; ++ k ) {
               if(i >> k & 1) continue;
               int nei = i | (1 << k), nej = (j * 10 + a[k] ) % K;
               f[ nej ][ nei ] = max( f[j][i] * 10 + a[k], f[ nej ][ nei ] ) ; 
           }
       }
   }
   for ( int i = K - 1; i >= 0; -- i) {
       if(f[i][(1 << n) - 1] != - 1) {
           cout << f[i][(1 << n) - 1] <<'\n';
           break;
       }
   }
   return 0;
}
posted @ 2022-05-02 16:11  qingyanng  阅读(347)  评论(0编辑  收藏  举报