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;
}
posted @ 2023-01-16 16:04  Forever1507  阅读(54)  评论(0编辑  收藏  举报