2020-2021 ACM-ICPC Latin American Regional
K - Keylogger
就是你可以显然的发现一个 \(O(n^3)\) 级别的动态规划。
设 \(dp_{i,j}\) 表示第 \(i\) 位密码,现在按的键是 \(j\) 的答案。
然后发现矩阵的每一行是单调递增的!
前缀和维护一下 \(dp\) 的值。
二!分!
做完了!
查看代码
#include<bits/stdc++.h>
const int mod=1e9+7;
using namespace std;
int k,l,n,t[755][755],p[100005],tot,dp[10005][755];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>k>>l;
for(int i=1;i<=k;++i){
for(int j=1;j<=k;++j){
cin>>t[i][j];
}
}
cin>>n;
for(int i=1;i<n;++i)cin>>p[i];
for(int i=1;i<=k;++i)dp[n][i]=i;
for(int i=n-1;i>=1;--i){
for(int j=1;j<=k;++j){
dp[i][j]=dp[i][j-1];
int pos1=upper_bound(t[j]+1,t[j]+1+k,p[i]+l)-t[j];
int pos2=lower_bound(t[j]+1,t[j]+1+k,p[i]-l)-t[j];
int x1=dp[i+1][pos1-1],x2=dp[i+1][pos2-1];
dp[i][j]=(1ll*dp[i][j]+1ll*x1-1ll*x2+1ll*mod)%mod;
}
}
cout<<dp[1][k];
return 0;
}
B - Beautiful Mountains
考虑一个事情,假设一个区间 \([L,R]\) 是一座"山",“山峰”是 \(k\neq L,R\),那么一定有\(0\le \min_{x \in [L+1,k]}dif_x\) 且 \(\max_{x \in [k+1,R]}dif_x\le 0\)
这个东西可以开两个 st 表维护,然后山峰再开一个 st 表。
出现 \(-1\) 的话,把差分弄成 \(0\),不管就可以了,原来的可以,\(-1\) 随便改。
查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],dp[100005][20],lg[100005],dp2[100005][20],dp3[100005][20];
void work(){
for(int j=1;j<=lg[n];++j){
for(int i=1;i+(1<<j)-1<=n;++i){
dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
}
}
for(int j=1;j<=lg[n];++j){
for(int i=1;i+(1<<j)-1<=n;++i){
dp2[i][j]=max(dp2[i][j-1],dp2[i+(1<<j-1)][j-1]);
}
}
for(int j=1;j<=lg[n];++j){
for(int i=1;i+(1<<j)-1<=n;++i){
if(a[dp3[i][j-1]]>a[dp3[i+(1<<j-1)][j-1]])dp3[i][j]=dp3[i][j-1];
else dp3[i][j]=dp3[i+(1<<j-1)][j-1];
}
}
return;
}
int calc1(int lt,int rt){
int base=lg[rt-lt+1];
if((1<<base)==rt-lt+1)return dp[lt][base];
return min(dp[lt][base],dp[rt-(1<<base)+1][base]);
}
int calc2(int lt,int rt){
int base=lg[rt-lt+1];
if((1<<base)==rt-lt+1)return dp2[lt][base];
return max(dp2[lt][base],dp2[rt-(1<<base)+1][base]);
}
int calc3(int lt,int rt){
int base=lg[rt-lt+1];
if((1<<base)==rt-lt+1)return dp3[lt][base];
if(a[dp3[lt][base]]>a[dp3[rt-(1<<base)+1][base]])return dp3[lt][base];
return dp3[rt-(1<<base)+1][base];
}
bool check(int l,int r){
int k=calc3(l+1,r-1);
if(calc1(l+1,k)>=0&&calc2(k+1,r)<=0)return 1;
return 0;
}
int main(){
cin>>n;
lg[0]=-1;
int lst=0;
for(int i=1;i<=n;++i){
cin>>a[i];
if(a[i]==-1||a[i-1]==-1){
dp[i][0]=dp2[i][0]=0;
}
else dp[i][0]=dp2[i][0]=a[i]-a[i-1];
dp3[i][0]=i;
lg[i]=lg[i>>1]+1;
}
work();
bool flg=0;
for(int i=3;i<=n;++i){
int j=1;
bool vis=0;
while(j+i-1<=n){
if(!check(j,j+i-1)){
vis=1;
break;
}
j+=i;
}
if(!vis&&(j>n||check(j,n)))flg=1;
}
if(flg)cout<<"Y";
else cout<<"N";
}
J - Job Allocator
这有啥好写的啊(
直接暴力啊。。。
查看代码
#include<bits/stdc++.h>
using namespace std;
int n,k;
int sum[9][9][9][9][9][9][9][9];
int cpu[100005][8],tot,num[8];
void add(int x){
int *c=cpu[x],cnt[8];
for(cnt[0]=0;cnt[0]<=c[0];cnt[0]++)
for(cnt[1]=0;cnt[1]<=c[1];cnt[1]++)
for(cnt[2]=0;cnt[2]<=c[2];cnt[2]++)
for(cnt[3]=0;cnt[3]<=c[3];cnt[3]++)
for(cnt[4]=0;cnt[4]<=c[4];cnt[4]++)
for(cnt[5]=0;cnt[5]<=c[5];cnt[5]++)
for(cnt[6]=0;cnt[6]<=c[6];cnt[6]++)
for(cnt[7]=0;cnt[7]<=c[7];cnt[7]++)
sum[cnt[0]][cnt[1]][cnt[2]][cnt[3]][cnt[4]][cnt[5]][cnt[6]][cnt[7]]++;
}
void del(int x){
int *c=cpu[x],cnt[8];
for(cnt[0]=0;cnt[0]<=c[0];cnt[0]++)
for(cnt[1]=0;cnt[1]<=c[1];cnt[1]++)
for(cnt[2]=0;cnt[2]<=c[2];cnt[2]++)
for(cnt[3]=0;cnt[3]<=c[3];cnt[3]++)
for(cnt[4]=0;cnt[4]<=c[4];cnt[4]++)
for(cnt[5]=0;cnt[5]<=c[5];cnt[5]++)
for(cnt[6]=0;cnt[6]<=c[6];cnt[6]++)
for(cnt[7]=0;cnt[7]<=c[7];cnt[7]++)
sum[cnt[0]][cnt[1]][cnt[2]][cnt[3]][cnt[4]][cnt[5]][cnt[6]][cnt[7]]--;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;++i){
char op;
int m;
cin>>op;
if(op=='C'){
cin>>m;
++tot;
while(m--){
int x;
cin>>x;
cpu[tot][x-1]++;
}
add(tot);
}
else if(op=='D'){
cin>>m;
del(m);
}
else{
cin>>m;
memset(num,0,sizeof(num));
while(m--){
int x;
cin>>x;
num[x-1]++;
}
cout<<sum[num[0]][num[1]][num[2]][num[3]][num[4]][num[5]][num[6]][num[7]]<<'\n';
}
}
return 0;
}
F - Fascinating Partitions
就是你考虑第 \(i\) 为要么以自己为最大值,要么就是在前面找第一个比自己大的捆绑进去,然后 dp 一下。
用单调栈维护即可。
查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
long long a[3000005],mini[3000005],dp[8005][8005];
int main(){
ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
a[0]=mini[0]=1e18;
memset(dp,0x7f,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;++i){
stack<int>stk;
stk.push(0);
for(int j=i;j<=n;j++){
mini[j]=dp[i-1][j-1];
while(a[stk.top()]<=a[j]){
mini[j]=min(mini[stk.top()],mini[j]);
stk.pop();
}
dp[i][j]=min(mini[j]+a[j],(!stk.empty())?dp[i][stk.top()]:(long long)1e18);
stk.push(j);
}
}
sort(a+1,a+n+1);
long long sum=0;
for(int i=1;i<=n;++i){
sum+=a[n-i+1];
cout<<dp[i][n]<<' '<<sum<<'\n';
}
return 0;
}