CF1553

CF1553

\(A\) , \(B\) 先不谈,我们先谈谈 \(C\) 的问题。
#\(C\) 状态#

C:

本题数据很小,可以考虑状压枚举,从0000000000到1111111111挨个尝试。

如何判断至少比几局呢?可以利用贪心的思想,从左到右把分加给双方,对于每一个位置,如果一方剩下全赢对方全输也无法胜利,即可停止比赛。

最后在所有状态中取最小值,即为答案。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;string s;
int main(){
	cin>>t;
	while(t--){
		cin>>s;int ans=10;
		for(int msk=0;msk<1024;msk++){
			bool fl=0;
			for(int i=0;i<10;i++)if((!!(msk&(1<<i)))!=(int)(s[i]-'0')&&s[i]!='?'){fl=1;break;}
			if(fl)continue;
			int a=0,b=0;
			for(int i=0;i<10;i++){
				if(i%2)a+=!!(msk&(1<<i));
				else b+=!!(msk&(1<<i));
				if(i==9||a+(10-i)/2<b||b+(9-i)/2<a){
					if(i==2)cout<<msk<<endl;
					ans=min(ans,i+1);
					break;
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

D

就类似于模拟特殊栈。

对于情况进行讨论:

  1. 首个字母改成退格:仅仅起到了删除某个字符的作用。
  2. 单独一个退格:这一个退格将原来的字符和前面一个字符通通删去,也就是连续删除了2个字符。
  3. 连续的 \(k\) 个退格:就是连续 \(k\) 个单独退格的效果。

从而,所有的删除操作,除去首位删除1字符外,均删除了连续2字符。

所以,\(n,m\) 奇偶性不同,必须删除首位。

用贪心,在 \(s\) 串匹配 \(t\) 串,如没匹配,说明这一位和下一位必须删除,检查是否匹配完成即可。

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		string s,t;
		cin>>s;
		cin>>t;
		int sl=s.length(),tl=t.length();
		string ss="";int j=0,k=0;
		if(sl%2!=tl%2) j=1;
		for(int i=j;i<sl;i++){
			if(s[i]==t[k]) k++;
			else i++;
			if(k>=tl) break;
		}
		if(k<tl) puts("NO");
		else puts("YES");
	}
	return 0;
}

E:

一句话题意:对于每个 \(k\) ,求最少多少次交换可以使一个排列变为另一个排列

做法:对于同一个数,若它在两个排列中的位置不同(记这样的数的总数为 \(s\) ),就建一条连接这两个位置的边,求得图的连通分量数 \(c\) ,答案就是 \(s−c\)

题中限制: \(m<\frac{n}{3}\) ,设两个排列位置一样的个数为 \(cnt_k\),

\(\sum cnt=n\) 所以满足 \(s\leq 2m\)\(k\) 的数量不超过 \(3!\).

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=3e5+13;
int n,m,cnt[N],p[N],ans[N];
vector<int> g[N];
bool vis[N];
inline void add_edge(int u,int v){g[u].pb(v);}
void dfs(int u){
	vis[u]=1;
	for(auto v:g[u])
		if(!vis[v]) dfs(v);
}
int T;
int main(){
    cin>>T;
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;++i) cnt[i]=0;
        for(int i=1;i<=n;++i){
            int x;scanf("%d",&x);
            p[x]=i;
            cnt[(i-x+n)%n]++;//这种情况下,x这个数的位置不需要动
        }
        int t=0;
        for(int k=0;k<n;++k){
            if(cnt[k]<n-2*m) continue;//不可能成功了,直接特判掉,能往下走的k最多3个
            for(int i=1;i<=n;++i) vis[i]=0,g[i].clear();
            for(int i=1;i<=n;++i){
                int pos=(i+k-1)%n+1;
                if(pos!=p[i]) add_edge(pos,p[i]);//加边
            }
            int c=0;
            for(int i=1;i<=n;++i){
                int pos=(i+k-1)%n+1;
                if(pos!=p[i]&&!vis[pos]) dfs(pos),++c;//求连通分量个数
            }
            if(n-cnt[k]-c<=m) ans[++t]=k;//最后判断是否可行
        }
        printf("%d ",t);for(int i=1;i<=t;++i) printf("%d ",ans[i]);putchar('\n');

    }
    // system("pause");
    return 0;
}

F:

没做出来真是哈哈了

线段树+树状数组,维护 \(i*a_i\)\(a_i\) 在值域维的区间和即可。

#include<bits/stdc++.h>	
#define ls tree[x].lson
#define rs tree[x].rson
#define tl tree[x].l
#define tr tree[x].r
typedef long long ll;
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T>
T& read(T& r) {
	r = 0; bool w = 0; char ch = getchar();
	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
	return r = w ? -r : r;
}
inline int lowbit(int x) { return x & (-x); }
const int N = 300010;
int n, a[N];
ll p[N];
struct BIT {
	int m;
	ll tree[N];
	void init(int x) {
		m = x;
		for(int i = 0; i <= m; ++i) tree[i] = 0;
	}
	void modify(int x, ll v) { for(; x <= m; x += lowbit(x)) tree[x] += v; }
	ll querysum(int x) { ll sumq = 0; for(; x; x -= lowbit(x)) sumq += tree[x]; return sumq; }
	ll query(int x, int y) { return querysum(y)-querysum(x-1); }
}bit1, bit2, tr2, tr3;
struct segment_tree {
	int trnt;
	struct SGT {
		int l, r, lson, rson;
		ll sum, tag;
	}tree[N << 1];
	inline void pushup(int x) { tree[x].sum = tree[ls].sum + tree[rs].sum; }
	inline void pushdown(int x) {
		if(tree[x].tag) {
			int p = tree[x].tag;
			tree[ls].sum += (tree[ls].r - tree[ls].l + 1) * p;
			tree[rs].sum += (tree[rs].r - tree[rs].l + 1) * p;
			tree[ls].tag += p;
			tree[rs].tag += p;
			tree[x].tag = 0;
		}
	}
	int build(int l, int r) {
		int x = ++trnt; tree[x].sum = 0;
		tl = l; tr = r;
		if(l == r) return x;
		ls = build(l, (l+r)>>1); rs = build(tree[ls].r+1, r);
		pushup(x); return x;
	}
	void modify(int x, int l, int r, ll v) {
		if(tl >= l && tr <= r) {
			tree[x].sum += (tree[x].r - tree[x].l + 1) * v;
			tree[x].tag += v;
			return ;
		}
		int mid = (tree[x].l + tree[x].r) >> 1;
		pushdown(x);
		if(mid >= l) modify(ls, l, r, v);
		if(mid < r) modify(rs, l, r , v);
		pushup(x);
	}
	ll query(int x, int l, int r) {
		if(tl >= l && tr <= r) return tree[x].sum;
		int mid = (tree[x].l + tree[x].r) >> 1; ll sumq = 0;
		pushdown(x);
		if(mid >= l) sumq += query(ls, l, r);
		if(mid < r) sumq += query(rs, l, r);
		pushup(x);
		return sumq;
	}
}tr1;
int mx = 0;
signed main() {
	read(n);
	for(int i = 1; i <= n; ++i) read(a[i]), mx = Max(mx, a[i]);
	bit1.init(mx); bit2.init(mx); tr2.init(mx); tr3.init(mx);
	for(int i = 1; i <= n; ++i) {
		p[i] += 1ll * a[i] * bit1.query(a[i]+1, mx);
		p[i] += bit2.query(1, a[i]-1);
		bit1.modify(a[i], 1);
		bit2.modify(a[i], a[i]);
	}
	tr1.build(1, mx);
	for(int i = 1; i <= n; ++i) {
		p[i] += tr1.query(1, 1, a[i]);
		for(int j = 1; j * a[i] <= mx; ++j) {
			p[i] -= j*a[i] * tr2.query(j*a[i], Min(mx, (j+1)*a[i]-1));
			p[i] += tr3.query(j*a[i], Min(mx, (j+1)*a[i]-1));
		}
		for(int j = 1; j * a[i] + 1 <= mx; ++j) {
			tr1.modify(1, j*a[i]+1, Min(mx, (j+1)*a[i]-1), 1);
			if((j+1)*a[i] <= mx)tr1.modify(1, (j+1)*a[i], (j+1)*a[i], -(Min(mx, (j+1)*a[i]-1) - (j*a[i]+1) + 1));
		}
		if(a[i] == 1) continue ;
		tr2.modify(a[i], 1);
		tr3.modify(a[i], a[i]);
	}
	for(int i = 1; i <= n; ++i) p[i] += p[i-1], printf("%lld ", p[i]);
    // system("pause");
	return 0;
}
posted @ 2021-08-18 19:34  Evitagen  阅读(41)  评论(0编辑  收藏  举报