zoukankan      html  css  js  c++  java
  • Coins

    题意:

    有1~n 面值的硬币,第i个硬币有ai个,求问这些硬币可以凑出多少个权值。

    解法:

    假定对于第i个硬币,选取了$x_i$个,则凑出的权值为$S = sum_{i=1}^n{x_i * i}$

    其中$x_i$可以表示为$x_i = k_i * frac{LCM(1,2..,n)}{i} + b_i$,从而有

    $$S = LCM(1,2...n)* sum_{i=1}^n {k_i} + sum_{i=1}^n{b_i * i}$$

    这样有$0<=bi<LCM/i $,$S$可以表示为若干个公比为$LCM$,首项为$sum_{i=1}^n{b_i * i}$,

    项数为$sum_{i=1}^n {k_i}$的等差数列的并。

    这样$a2_i = min { a_i  mod  frac{LCM}{i} + frac{LCM}{i}, a_i } $,二进制拆分+bitset压位计算出

    $O(n^2 * LCM *log(a2_i) / 64)$,进而计算出首项,合并等差数列即可。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <bitset>
     5 #include <ctime>
     6 
     7 #define N 17
     8 #define LL long long
     9 #define M 360361
    10 
    11 using namespace std;
    12 
    13 int n,L,a[N];
    14 bool flag[M];
    15 bitset<M*N> f;
    16 
    17 LL gcd(LL a,LL b)
    18 {
    19     if(!b) return a;
    20     return gcd(b,a%b);
    21 }
    22 
    23 int main()
    24 {
    25 //    freopen("test.txt","r",stdin);
    26     while(~scanf("%d",&n))
    27     {
    28         L=1;
    29         int sum=0;
    30         LL ans=0,K=0;
    31         for(int i=2;i<=n;i++) L = L*i/gcd(L,i);
    32         for(int i=1;i<=n;i++)
    33         {
    34             scanf("%d",&a[i]);
    35             int tmp = min(a[i], a[i]%(L/i) + (L/i));
    36             K += (a[i]-tmp) / (L/i);
    37             a[i]=tmp;
    38             sum+=i*a[i];
    39         }
    40         f.reset();
    41         f[0]=1;
    42         for(int i=1;i<=n;i++)
    43         {
    44             int cnt=a[i];
    45             for(int j=1;cnt;j<<=1)
    46             {
    47                 int tmp=min(j,cnt);
    48                 if(tmp*(LL)i > sum) break;
    49                 f |= (f << (tmp*i));
    50                 cnt-=tmp;
    51             }
    52         }
    53         for(int i=0;i<=sum;i++)
    54         {
    55             if(!f[i]) continue;
    56             ans++;
    57             bool flag=0;
    58             for(int j=i-L;j>=0;j-=L) if(f[j]) flag=1;
    59             if(!flag) ans += K;
    60         }
    61         cout << ans << endl;
    62     }
    63     return 0;
    64 }
    View Code
  • 相关阅读:
    contentSize,contentOffset,contentInset整理
    UITableViewCell的移动
    怎么修改Xcode新项目或新文件最上面的Creat By XXX
    objc_setAssociatedObject 关联对象
    Python strip()方法
    Python函数中*args和**kwargs来传递变长参数的用法
    python闭包
    Grand Garden思维题
    Circles Inside a Square(几何题)
    Matrix Transformation(模拟)
  • 原文地址:https://www.cnblogs.com/lawyer/p/6481634.html
Copyright © 2011-2022 走看看