【解题报告】UOJ-Round泛做

  • 本文为博主原创,未经许可不得转载

【UR #1】缩进优化

首先将问题转化为求最多能缩掉多少空格

考虑对于一个$x$,每个$a_i$的贡献是$\left[\frac{a_i}{x} \right] (x-1)$

所以我们的做法就是枚举x,然后对$\left[\frac{a_i}{x} \right]$使用下底分块统计贡献

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<bits/stdc++.h>
#define FILE "read"
#define MAXN 1000100
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
using namespace std;
typedef long long ll;
const int N=1e6;
int n,a[MAXN],cnt[MAXN];
ll ans,sum;
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int main(){
//freopen(FILE".in","r",stdin);
//freopen(FILE".out","w",stdout);
n=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i) sum+=a[i];
for(int i=1;i<=n;++i) cnt[a[i]]++;
for(int i=N;i;--i) cnt[i]+=cnt[i+1];
for(int i=1;i<=N;++i){
int temp=0;
for(int j=i;j<=N;j+=i)
temp+=cnt[j];
cmax(ans,(ll)temp*(i-1));
}
printf("%lld\n",sum-ans);
return 0;
}

  

  

【UR #1】外星人

看到这类问题考虑$dp$

设$f[j]$表示答案为j时的方案数

那么考虑一个小于等于$j$的$a_k$,$f[j]$可以转移到$f[j mod a_k]$

转移时搞一波组合数,具体见题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<bits/stdc++.h>
#define FILE "read"
#define MAXN 5050
using namespace std;
const int mod=998244353;
int n,m,N,a[MAXN],inv[MAXN],fac[MAXN],cnt[MAXN],f[MAXN];
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int sub(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return 1LL*a*b%mod;}
inline int fast(int a,int b){int ret(1);for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
void pre(){
N=5000; fac[0]=1;
for(int i=1;i<=N;++i) fac[i]=mul(fac[i-1],i);
inv[N]=fast(fac[N],mod-2);
for(int i=N-1;i>=0;--i) inv[i]=mul(inv[i+1],i+1);
}
int main(){
//freopen(FILE".in","r",stdin);
//freopen(FILE".out","w",stdout);
n=read(); m=read(); pre();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i) cnt[a[i]]++;
for(int i=1;i<=N;++i) cnt[i]+=cnt[i-1];
sort(a+1,a+n+1); f[m]=mul(fac[n],inv[cnt[m]]);
for(int j=m;j>=0;--j)if(f[j]){
for(int k=1;k<=n&&a[k]<=j;++k){
f[j%a[k]]=add(f[j%a[k]],mul(f[j],mul(fac[cnt[j]-1],inv[cnt[j%a[k]]])));
}
}
int ans=a[1]-1;
while(!f[ans]) --ans;
printf("%d\n%d\n",ans,f[ans]);
return 0;
}

【UR #2】猪猪侠再战括号序列

从左到右扫描,遇到右括号就和离他最近的左括号交换

这样既能保证扫描过的地方都是左括号,又能保证每次翻转时只交换端点的括号,妙哉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<bits/stdc++.h>
#define FILE "read"
#define MAXN 200100
using namespace std;
int cnt,L[MAXN],R[MAXN];
char ch[MAXN];
int main(){
//freopen(FILE".in","r",stdin);
//freopen(FILE".out","w",stdout);
scanf("%s",ch+1); int n=strlen(ch+1)/2,cur=0;
for(int i=1;i<=n;++i)if(ch[i]==')'){
if(!cur) cur=i; ++cur;
while(ch[cur]!='(') ++cur;
L[++cnt]=i; R[cnt]=cur; swap(ch[i],ch[cur]);
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;++i) printf("%d %d\n",L[i],R[i]);
return 0;
}
文章目录
  1. 1. 【UR #1】缩进优化
  2. 2. 【UR #1】外星人
  3. 3. 【UR #2】猪猪侠再战括号序列
,