【UOJ Round #1】
枚举/DP+排列组合
缩进优化
QAQ我当时一直在想:$min\{ \sum_{i=1}^n (\lfloor\frac{a[i]}{x}\rfloor + a[i] \ mod\ x) \}$
然而并不会做啊……一点思路也没有……主要是后面那个取模非常难受……
其实正解有点逆向思维的感觉:$ans=\sum_{i=1}^n a[i] - max\{ \sum_{i=1}^n \lfloor \frac{a[i]}{x}\rfloor *(x-1) \} $
也就是先将a[i]全部加起来,然后再使得被缩掉的部分最大。
然后……枚举x,枚举x的倍数,数一下除以x为 i 的有多少个就可以了……$O(nlogn)$
1 //UOJ Round #1 A 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<iostream> 7 #include<algorithm> 8 #define rep(i,n) for(int i=0;i<n;++i) 9 #define F(i,j,n) for(int i=j;i<=n;++i) 10 #define D(i,j,n) for(int i=j;i>=n;--i) 11 #define pb push_back 12 using namespace std; 13 inline int getint(){ 14 int v=0,sign=1; char ch=getchar(); 15 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 16 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 17 return v*sign; 18 } 19 const int N=1e6+10,INF=~0u>>2; 20 typedef long long LL; 21 /******************tamplate*********************/ 22 23 int a[N],c[N],n; 24 int main(){ 25 #ifndef ONLINE_JUDGE 26 freopen("A.in","r",stdin); 27 freopen("A.out","w",stdout); 28 #endif 29 n=getint(); 30 LL sum=0,ans=0; 31 int mx=0; 32 F(i,1,n) a[i]=getint(),c[a[i]]++,sum+=a[i],mx=max(mx,a[i]); 33 D(i,mx,1) c[i]+=c[i+1]; 34 35 F(x,1,mx){ 36 LL tmp=0; int i; 37 for(i=1;(i+1)*x<=mx;i++) 38 tmp+=(c[i*x]-c[(i+1)*x])*i; 39 tmp+=c[i*x]*i; 40 ans=max(ans,tmp*(x-1)); 41 } 42 printf("%lld\n",sum-ans); 43 return 0; 44 }
外星人
Orz 题解
我只想到如果 x<a[i] ,那么a[i]之后放到哪里都不会有影响了……
对,我们只需要$f[i]$作为状态就够了。用$f[i]$表示$x=i$且只考虑手指数小于等于$i$的外星人的情况下的最优解与方案数。
怎么转移呢?我们在手指数小于等于$i$的外星人中选一个$a_k$作为下一个发送信息的外星人,显然这个外星人一定是有效外星人。那么考虑手指数介于$(i\ mod\ a_k , i]$的外星人,我们发现只要把他们随便插入到$f[i \ mod\ a_k]$的最优解排列中去就可以了。这个显然可以用最简单的组合数学解决。方案数即$\frac{(N_i -1)!}{N_{i\ mod\ a_k}!}$。其中$N_c$表示手指数不超过$c$的外星人个数。
1 //UOJ Round #1 B 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<iostream> 7 #include<algorithm> 8 #define rep(i,n) for(int i=0;i<n;++i) 9 #define F(i,j,n) for(int i=j;i<=n;++i) 10 #define D(i,j,n) for(int i=j;i>=n;--i) 11 #define pb push_back 12 using namespace std; 13 inline int getint(){ 14 int v=0,sign=1; char ch=getchar(); 15 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 16 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 17 return v*sign; 18 } 19 const int N=5010,INF=~0u>>2,P=998244353; 20 typedef long long LL; 21 /******************tamplate*********************/ 22 23 int n,m,a[N],c[N],f[N][2],fac[N],inv[N]; 24 int main(){ 25 #ifndef ONLINE_JUDGE 26 freopen("B.in","r",stdin); 27 freopen("B.out","w",stdout); 28 #endif 29 n=getint(); m=getint(); 30 int mx=m; 31 F(i,1,n) a[i]=getint(),c[a[i]]++,mx=max(mx,a[i]); 32 sort(a+1,a+n+1); 33 F(i,1,mx) c[i]+=c[i-1]; 34 35 fac[0]=1; 36 F(i,1,mx) fac[i]=(LL)fac[i-1]*i%P; 37 inv[0]=inv[1]=1; 38 F(i,2,mx) inv[i]=P-(LL)(P/i)*inv[P%i]%P; 39 F(i,2,mx) inv[i]=(LL)inv[i]*inv[i-1]%P; 40 41 F(i,0,m){ 42 if (c[i]==0) {f[i][0]=i,f[i][1]=1;continue;} 43 for(int j=1;a[j]<=i && j<=n;j++) 44 if (f[i%a[j]][0]>f[i][0]){ 45 f[i][0]=f[i%a[j]][0]; 46 f[i][1]=(LL)fac[c[i]-1]*inv[c[i%a[j]]]%P*f[i%a[j]][1]%P; 47 }else if (f[i%a[j]][0]==f[i][0]){ 48 f[i][1]=(f[i][1]+(LL)fac[c[i]-1]*inv[c[i%a[j]]]%P*f[i%a[j]][1]%P)%P; 49 } 50 } 51 f[m][1]=(LL)f[m][1]*fac[c[mx]]%P*inv[c[m]]%P; 52 printf("%d\n%d\n",f[m][0],f[m][1]); 53 return 0; 54 }