• AtCoder Regular Contest 098


    AtCoder Regular Contest 098


    C - Attention

    题意:有n个人站成一排,每个人可能面向东或西。

    现在要选一个人,让其他人转向所选的那个人。求最小转向次数。

    分析:模拟即可。

    代码:

        #include <cstdio>
        #include <cstring>
        #include <algorithm>
        #include <cstdlib>
        #include <map>
        using namespace std;
        typedef long long ll;
        #define GG puts("FUCK")
        #define N 300050
        char str[N];
        int n,sum;
        int main() {
        	scanf("%d%s",&n,str+1);
        	int i;
        	for(i=1;i<=n;i++) {
        		if(str[i]=='E') sum++;
        	}
        	int now=0,ans=1<<30;
        	for(i=1;i<=n;i++) {
        		if(str[i]=='E') sum--;
        		ans=min(ans,now+sum);
        		if(str[i]=='W') now++;
        	}
        	printf("%d
    ",ans);
        }
    

    D - Xor Sum 2

    题意:给你一个长度为n的序列,求合法连续子序列个数,合法定义为和等于他们异或起来。

    分析:可以发现这样的序列长度最多为20,暴力/双指针即可。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <map>
    using namespace std;
    typedef long long ll;
    #define GG puts("FUCK")
    #define N 200050
    int n,a[N],h[30],num;
    void add(int x) {
    	int i;
    	for(i=19;i>=0;i--) if(x&(1<<i)) {
    		h[i]++; if(h[i]==2) num++;
    	}
    }
    void del(int x) {
    	int i;
    	for(i=19;i>=0;i--) if(x&(1<<i)) {
    		h[i]--; if(h[i]==1) num--;
    	}
    }
    int main() {
    	scanf("%d",&n);
    	int i;
    	for(i=1;i<=n;i++) {
    		scanf("%d",&a[i]);
    	}
    	ll ans=0;
    	int j=1;
    	for(i=1;i<=n;i++) {
    		add(a[i]);
    		while(j<=i&&num) del(a[j]),j++;
    		ans+=(i-j+1);
    	}
    	printf("%lld
    ",ans);
    }
    

    E - Range Minimum Queries

    题意:给你一个长度为n的序列,你可以进行Q次操作,每次操作把一段长度为K的连续子序列的最小值删除。

    求删掉的数中最大-最小的最小值。

    分析:枚举删除的最小值,然后比这个数小的不能被选到,相当于把序列分成几段,每段把可以删的放在一起。

    然后拿第Q小的能删的数更新答案。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 2050
    int n,a[N];
    int K,Q,b[N],c[N],ans=1<<30,tot;
    void add(int l,int r) {
    	int i;
    	for(i=l;i<=r;i++) b[i]=a[i];
    	sort(b+l,b+r+1);
    	for(i=l;i<=r-K+1;i++) c[++tot]=b[i];
    }
    void solve(int x) {
    	int i,lst=1; tot=0;
    	for(i=1;i<=n;i++) {
    		if(a[i]<x) {
    			if(lst<=i-1) add(lst,i-1);
    			lst=i+1;
    		}
    	}
    	if(lst<=n) add(lst,n);
    	sort(c+1,c+tot+1);
    	if(tot<Q) return ;
    	ans=min(ans,c[Q]-c[1]);
    }
    int main() {
    	int i;
    	scanf("%d%d%d",&n,&K,&Q);
    	for(i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(i=1;i<=n;i++) {
    		solve(a[i]);
    	}
    	printf("%d
    ",ans);
    }
    

    F - Donation

    题意:给出一个n个点,m条边的无向图。每个点有权值ai,bi。

    你可以任选一个点当做起点,你初始拥有的钱需要大于等于aS。每次移动的时候钱数也要大于等于aT。

    你需要对每个点捐出bi的钱,求初始最少有多少钱。

    分析:

    发现对于每个点在最后一次贡献不会更差。

    把A的约束转化一下,设Ci=max(Ai-Bi,0)。这个约束表示任何时候站在i这个点至少要有Ci。

    然后贪心的想,Ci大的先遍历显然不会更差。

    于是这样:找到C最大的点x,把x删掉后产生了T个连通块G1,G2..GT。

    显然有一种最优的方案是贡献x后进入了一个连通块就不再出来。

    然后递归每个连通块,用这一层的根连向上一层的根,这样就形成了一棵树。

    这棵树满足任意一个点的Ci大于等于子树的点的Cj。

    可以DP,设f[x]表示x的子树符合条件的最小初始钱数。

    初始值f[x]=s[x]+c[x],其中s[x]表示x的子树b之和。

    然后考虑把儿子的贡献拽到x的后面,有f[x]=min(f[x],s[x]-s[to[i]]+max(f[to[i]],c[x]))

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    typedef long long ll;
    #define GG puts("FUCK")
    #define N 100050
    int head[N],to[N],nxt[N],fa[N],a[N],b[N],c[N],n,m,vis[N],id[N],cnt;
    vector<int>v[N];
    ll f[N],s[N];
    int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
    bool cmp(int x,int y) {return c[x]<c[y];}
    inline void add(int u,int v) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    }
    void dfs(int x) {
    	int i; s[x]=b[x];
    	for(i=head[x];i;i=nxt[i]) {
    		dfs(to[i]); s[x]+=s[to[i]];
    	}
    	f[x]=s[x]+c[x];
    	for(i=head[x];i;i=nxt[i]) {
    		f[x]=min(f[x],s[x]-s[to[i]]+max(f[to[i]],1ll*c[x]));
    	}
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	int i,x,y,j;
    	for(i=1;i<=n;i++) {
    		scanf("%d%d",&a[i],&b[i]); c[i]=max(a[i]-b[i],0); fa[i]=id[i]=i;
    	}
    	for(i=1;i<=m;i++) {
    		scanf("%d%d",&x,&y); v[x].push_back(y); v[y].push_back(x);
    	}
    	sort(id+1,id+n+1,cmp);
    	for(i=1;i<=n;i++) {
    		x=id[i]; int lim=v[x].size(); vis[x]=1;
    		for(j=0;j<lim;j++) {
    			y=v[x][j]; if(!vis[y]) continue;
    			y=find(y);
    			if(x!=y) {
    				fa[y]=x; add(x,y);
    			}
    		}
    	}
    	dfs(id[n]);
    	printf("%lld
    ",f[id[n]]);
    }
    
  • 相关阅读:
    C语言、指针的指针和野指针的问题
    常见证书格式和转换
    cation,validation,qualification有何区别
    Cygwin + OpenSSH FOR Windows的安装配置
    python static variable
    45个与众不同的非常棒网页设计案例
    65个精心设计的富有灵感的电子商务网站案例
    60个抢眼的企业网站设计案例
    26个有用的创建视觉图片网站的jQuery插件
    Android 图像用户界面免费的PSD设计文件
  • 原文地址:https://www.cnblogs.com/suika/p/9252551.html
Copyright © 2020-2023  润新知