• Educational Codeforces Round 94 (Div. 2) 题解 (CDE)


    C. Binary String Reconstruction

    大意:字符串w是由字符串s转换过来的,其中w[i]为'1'当且仅当s[i-x]或者s[i+x]为'1'。已知w,求s

    容易得知s[i]为'0'的时候,w[i-x]和w[i+x]一定都是'0'。我们让这些位赋值为'0',其他位都是'1',然后检验一下

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=200010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
    #define int ll
    char s[N],ans[N];
    void Solve(){
    	scanf("%s",s); int n=strlen(s),x=read();
    	repeat(i,0,n)ans[i]='1';
    	repeat(i,0,n)
    	if(s[i]=='0'){
    		if(i-x>=0)ans[i-x]='0';
    		if(i+x<n)ans[i+x]='0';
    	}
    	repeat(i,0,n)
    	if(s[i]=='1'){
    		if(i-x>=0 && ans[i-x]=='1');
    		else if(i+x<n && ans[i+x]=='1');
    		else{puts("-1"); return;}
    	}
    	repeat(i,0,n)putchar(ans[i]);
    	puts("");
    }
    signed main(){
    	//freopen("data.txt","r",stdin);
    	int T=1; T=read();
    	while(T--)Solve();
    	return 0;
    }
    

    D. Zigzags

    大意:给定 (n) 个数 (a_i),求有多少个 ((i,j,k,l)) 满足 (i<j<k<l)(a_i=a_k,a_j=a_l)

    看了一下gyz代码,我深刻认识到自己与神仙的差距
    统计每种值的前缀个数和后缀个数,遍历 j 和 k,直接可以算出 i 和 l 的个数
    O(n^2)
    以下是原题解

    (a_i) 看成颜色。首先固定两个颜色,然后让 (i,k) 枚举第一个颜色,用 lower_bound 求出在第二个颜色集合中,(i,k) 之间、(k,n) 之间有多少数(即计算 (j,l) 的方案数),相乘

    特判一下 (a_i=a_j=a_k=a_l) 的情况

    (我对所有颜色集合排了个序,然后查找就小的集合往大的集合找,可以加速,不知道不加速能不能过)

    复杂度我也不知道

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=3010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
    #define int ll
    vector<int> a[N];
    ll ans;
    void work(const vector<int> &a,const vector<int> &b){
    	repeat(i,0,a.size()){
    		int p1=lower_bound(b.begin(),b.end(),a[i])-b.begin();
    		repeat(j,i+1,a.size()){
    			int p2=lower_bound(b.begin(),b.end(),a[j])-b.begin();
    			ans+=(p2-p1)*p1+(p2-p1)*(b.size()-p2);
    		}
    	}
    }
    void Solve(){
    	int n=read(); ans=0;
    	repeat(i,1,n+1)a[i].clear();
    	repeat(i,1,n+1){
    		int t=read();
    		a[t].push_back(i);
    	}
    	sort(a+1,a+n+1,[](const vector<int> &a,const vector<int> &b){
    		return a.size()<b.size();
    	});
    	repeat(i,1,n+1)sort(a[i].begin(),a[i].end());
    	repeat(i,1,n+1){
    		repeat(j,i+1,n+1)
    			work(a[i],a[j]);
    		if(a[i].size()>=4){
    			int n=a[i].size();
    			ans+=n*(n-1)*(n-2)*(n-3)/(2*3*4);
    		}
    	}
    	printf("%lld
    ",ans);
    }
    signed main(){
    	//freopen("data.txt","r",stdin);
    	int T=1; T=read();
    	while(T--)Solve();
    	return 0;
    }
    

    E. Clear the Multiset

    大意:给定n个数ai,操作1:选择一个区间,每个数减1;操作2:选择一个数,变为任意比原来小的数。求把所有数变成0的最小操作数

    dp,我一直在死磕贪心,最终还是没做出来,还是zkx告诉我的dp呜呜呜

    dp[i][j]表示处理到第i个数,j个操作1仍然有效的答案

    显然,处理到第i个数时,我们可以用操作1解决ai,也可以用操作2解决ai。如果用了操作2,那么状态转移方程 (dp[i][min(a[i],j)]=dp[i-1][j]+1),这个 min 是因为最多只能存a[i]个操作1,多余的操作1肯定失效了。如果用了操作1,(注意这种情况只有 (a[i]le n) 的时候才会考虑,不然re)那么状态转移方程 (dp[i][a[i]]=dp[i-1][j](jge a[i]),dp[i][a[i]]=dp[i-1][j]+a[i]-j(j<a[i])),后面那个 (a[i]-j) 是补齐不够的操作1

    官方题解不是dp,容我观摩一下
    题解说,对于一个区间,我们要么用操作2删掉每个数(代价为区间长度),要么不断用操作1直到最小的那个数变成0然后对剩下的两个区间进行同样操作,这两个方案取 min 即可
    这个操作是 (O(n^2)) 的。显然瓶颈主要在RMQ问题上,如果用线段树或者st表维护区间最小值的下标,那么可以优化到 (O(nlog n))。当然如果骚一点是可以 (O(n)) 的(指笛卡尔树优化Four Russian算法)

    不是dp的代码:(没优化,(O(n^2))

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=5010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
    #define int ll
    int a[N];
    int work(int l,int r,int base){
    	if(l>r)return 0;
    	int p=min_element(a+l,a+r+1)-a;
    	return min(r-l+1,
    		work(l,p-1,a[p])+a[p]-base+work(p+1,r,a[p]));
    }
    void Solve(){
    	int n=read();
    	repeat(i,0,n)a[i]=read();
    	printf("%lld
    ",work(0,n-1,0));
    }
    signed main(){
    	//freopen("data.txt","r",stdin);
    	int T=1; //T=read();
    	while(T--)Solve();
    	return 0;
    }
    

    dp代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=5010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
    #define int ll
    int a[N],dp[N][N];
    #define MIN(x,y) x=min(x,y)
    void Solve(){
    	int n=read();
    	repeat(i,1,n+1)a[i]=read();
    	repeat(j,1,n+1)dp[0][j]=j;
    	repeat(i,1,n+1){
    		repeat(j,0,n+1)dp[i][j]=inf;
    		repeat(j,0,n+1)MIN(dp[i][min(a[i],j)],dp[i-1][j]+1);
    		if(a[i]<=n)
    		repeat(j,0,n+1)
    		if(j>=a[i])
    			MIN(dp[i][a[i]],dp[i-1][j]);
    		else
    			MIN(dp[i][a[i]],dp[i-1][j]+a[i]-j);
    	}
    	ll ans=inf;
    	repeat(j,0,n+1)ans=min(ans,dp[n][j]);
    	printf("%lld
    ",ans);
    }
    signed main(){
    	//freopen("data.txt","r",stdin);
    	int T=1; //T=read();
    	while(T--)Solve();
    	return 0;
    }
    
  • 相关阅读:
    python 的rjust函数
    二叉树
    实验四 系统调用
    实验三:跟踪分析Linux内核的启动过程
    ZigZag Conversion1
    Oracle数据文件管理
    Java中hashcode,equals和==
    浅析Java中HashMap的实现
    迷宫(栈,堆,队列)
    TCP/IP的三次握手协议
  • 原文地址:https://www.cnblogs.com/axiomofchoice/p/13562839.html
Copyright © 2020-2023  润新知