CF1783 A-F 题解

比赛链接:https://codeforces.com/contest/1783

连续三场出4题,还行(其实感觉有两场的E都是会做的)

A
水题

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;
int n,a[200005];
int cmp(int a,int b){return a>b;}
void solve(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	sort(a+1,a+n+1,cmp);
	if(a[1] == a[2])swap(a[2], a[n]);
	if(a[1] == a[2])return (void)puts("NO");
	puts("YES");
	for(int i=1;i<=n;i++)printf("%d ",a[i]);puts("");
}

signed main(){
	int te;scanf("%d",&te);
	while(te--)solve();

	return 0;
}

B
考虑蛇形构造,像这样:
1 9 2
6 5 8
4 7 3

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;
int n,a[55][55];
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
int in(int x,int y){
	if(x>=1&&x<=n&&y>=1&&y<=n&&a[x][y]==0)return 1;
	return 0;
}
void solve(){
	scanf("%d",&n);
	memset(a,0,sizeof a);
	a[1][1] = 1;
	int x=1,y=1,curx=0;
	int now=1,de=n*n-1;
	for(int i=2;i<=n*n;i++,--de){
		if(i%2==0)now+=de;
		else now-=de;
		if(in(x+dx[curx],y+dy[curx])){
			x += dx[curx], y += dy[curx];
			a[x][y] = now;
		}else{
			curx = (curx+1)%4;
			x += dx[curx], y += dy[curx];
			a[x][y] = now;
		}
	}
	for(int i=1;i<=n;i++,puts(""))
		for(int j=1;j<=n;j++)printf("%d ",a[i][j]);
}

signed main(){
	int te;scanf("%d",&te);
	while(te--)solve();

	return 0;
}

C
二分排名 x,然后判断一下能不能和原来排名为 x 的人比一比

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f,maxn=5e5+5;
int n,m;
struct node{
	int v,id;
}a[maxn],b[maxn];
int cmp(node a,node b){
	return a.v<b.v;
}
int check(int rk){
	int im = n-rk+1;
	int mm = m, now = 0;
	for(int i=1;i<=n;i++)
		if(mm - a[i].v >= 0){
			mm -= a[i].v;
			++ now;
		}else break;
	if(now >= im)return 1;
	
	if(m < b[im].v)return 0;
	mm = m - b[im].v, now = 1;
	for(int i=1;i<=n;i++){
//		printf("! %d %d\n",im,a[i].id);
		if(a[i].id == im)continue;
		if(mm - a[i].v >= 0){
			mm -= a[i].v;
			++ now;
		}else break;
	}
	if(now >= im-1)return 1;
	return 0;
}
void solve(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i].v), a[i].id = i;
	for(int i=1;i<=n;i++)b[i] = a[i];
	sort(a+1,a+n+1,cmp);
	int l=1,r=n,ans=n+1;
	while(l<=r){
		int mid=l+r>>1;
		if(check(mid))r=mid-1,ans=mid;
		else l=mid+1;
	}
	printf("%d\n",ans);
}

signed main(){
	int te;scanf("%d",&te);
	while(te--)solve();

	return 0;
}

D

考虑dp,设 \(dp[i][S]\) 表示考虑到第 \(i\) 个位置,此处现在的值是 \(S\) 的方案数
\(dp[i][S] \rightarrow dp[i+1][S+a[i+1]] or dp[i+1][a[i+1]-S]\),注意一下可能有负数,另外如果 S 是0的话只能转移其中一个
有负数所以第二维 +一个大数 就行了,这里偷懒用了unordered_map,贴时限过的(不过卡这个的人也真是sxbk)

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 305, mod = 998244353;

int n,a[maxn];
unordered_map<int,int>dp[2];

signed main(){
//	freopen("D.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	dp[2&1][a[2]] = 1;
	for(int i=2;i<=n-1;i++){
		dp[i+1&1].clear();
		for(auto pr : dp[i&1]){
			int lstt = pr.first, dpp = pr.second;
			(dp[i+1&1][lstt + a[i+1]] += dp[i&1][lstt]);
			if(dp[i+1&1][lstt+a[i+1]]>=mod)dp[i+1&1][lstt+a[i+1]]-=mod;
			
			if(lstt == 0)continue;
			(dp[i+1&1][a[i+1] - lstt] += dp[i&1][lstt]) %= mod;
		}
	}
	ll ans=0;
	for(auto pr : dp[n&1])
		(ans += pr.second) %= mod;
	cout<<ans;

	return 0;
}

E
当时过了D之后就摆了,结果仔细一看我会做。。
考虑什么样的 \(k\) 符合条件:\((m-1)k<a[i]<=mk \and (m-1)<b[i]\),对任意 \(i\) 成立
首先,如果 \(a[i]<=b[i]\) 那么任意的 \(k\) 都一定符合条件,故只考虑 \(a[i] > b[i]\)
注意到一开始的条件就等价于 \([b[i],a[i])\) 不能有 \(k\) 的倍数
直接 枚举 \(k\) 计算即可,复杂度是调和级数
(另外直接暴力分解质因数也是可以过的)

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;
int n,a[maxn],b[maxn],cf[maxn];
set<int>ban;
void cutdiv(int x){
	for(int i=1;i*i<=x;i++)
		if(x%i == 0)
			ban.insert(i), ban.insert(x/i);
}
void solve(){
	ban.clear();
	scanf("%d",&n);
	for(int i=0;i<=n+1;i++)cf[i] = 0;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)scanf("%d",&b[i]);
	
	for(int i=1;i<=n;i++)
		if(a[i] > b[i])
			++ cf[b[i]], -- cf[a[i]];
	
	for(int i=2;i<=n;i++)
		cf[i] += cf[i-1];
	vector<int>vi;
	for(int k=1;k<=n;k++){
		int gg = 0;
		for(int i=k;i<=n;i+=k)
			if(cf[i]){gg = 1;break;}
		if(!gg)vi.push_back(k);
	}
	printf("%d\n",vi.size());
	for(int u : vi)printf("%d ",u);puts("");
}

signed main(){
	int te;scanf("%d",&te);
	while(te--)solve(); 

	return 0;
}

F
对于一个排列而言,如果 \(i->p[i]\) 连一条有向边,那么这个排列排好的步数就是 所有环的(size-1)之和
也就是说,对于一个环,让其中一个元素不动,其它元素都动
然后考虑怎么拓展到2个排列
首先发现,要求的是使操作数最小,也就是使不变的元素最多。考虑最多有多少个元素不变
由于一个环中有且仅有一个元素不变,因此如果固定住了一个元素不变,那么在两个排列中分别对应的这个元素所在的环都只能让这一个元素不变(其它的元素的并集就不能选了)。因此如果将一个排列上的每个环与另一个排列的环连边(如果存在一个 \(i\) 使得两个环都含有 \(i\) 的话),容易发现这是个二分图,而所求的最多个不变元素就是这个图的最大匹配,网络流解决

// LUOGU_RID: 99283169
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 10005;

template<class T>
struct Flow {
    const int n;
    struct Edge {
        int to;
        T cap;
        Edge(int to, T cap) : to(to), cap(cap) {}
    };
    std::vector<Edge> e;
    std::vector<std::vector<int>> g;
    std::vector<int> cur, h;
    Flow(int n) : n(n), g(n) {}
    
    bool bfs(int s, int t) {
        h.assign(n, -1);
        std::queue<int> que;
        h[s] = 0;
        que.push(s);
        while (!que.empty()) {
            const int u = que.front();
            que.pop();
            for (int i : g[u]) {
                auto v=e[i].to, c=e[i].cap;
                if (c > 0 && h[v] == -1) {
                    h[v] = h[u] + 1;
                    if (v == t) {
                        return true;
                    }
                    que.push(v);
                }
            }
        }
        return false;
    }
    
    T dfs(int u, int t, T f) {
        if (u == t) {
            return f;
        }
        auto r = f;
        for (int &i = cur[u]; i < int(g[u].size()); ++i) {
            const int j = g[u][i];
            auto v=e[j].to, c=e[j].cap;
            if (c > 0 && h[v] == h[u] + 1) {
                auto a = dfs(v, t, std::min(r, c));
                e[j].cap -= a;
                e[j ^ 1].cap += a;
                r -= a;
                if (r == 0) {
                    return f;
                }
            }
        }
        return f - r;
    }
    void addEdge(int u, int v, T c) {
        g[u].push_back(e.size());
        e.emplace_back(v, c);
        g[v].push_back(e.size());
        e.emplace_back(u, 0);
    }
    T maxFlow(int s, int t) {
        T ans = 0;
        while (bfs(s, t)) {
            cur.assign(n, 0);
            ans += dfs(s, t, std::numeric_limits<T>::max());
        }
        return ans;
    }
};

int n,a[maxn],b[maxn],bela[maxn],belb[maxn];

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)scanf("%d",&b[i]);
	memset(bela,-1,sizeof bela);
	memset(belb,-1,sizeof belb);
	
	for(int i=1;i<=n;i++)
		if(~bela[i])continue;
		else{
			int j = i;
			while(bela[j] == -1){
				bela[j] = i;
				j = a[j];
			}
		}
	for(int i=1;i<=n;i++)
		if(~belb[i])continue;
		else{
			int j = i;
			while(belb[j] == -1){
				belb[j] = i;
				j = b[j];
			}
		}
	
	Flow<int> flow(2*n + 3);
	for(int i=1;i<=n;i++)
		flow.addEdge(bela[i], n + belb[i], 1);
	for(int i=1;i<=n;i++)
		flow.addEdge(2*n+1, i, 1),
		flow.addEdge(n+i, 2*n+2, 1);
	flow.maxFlow(2*n+1, 2*n+2);
	vector<int>ans;
	for(int i=0;i<n;i++)
		if(flow.e[2*i].cap)ans.push_back(i + 1);
	printf("%d\n",ans.size());
	for(int u : ans)printf("%d ",u);puts("");
		
	return 0;
}
posted @ 2023-01-10 22:33  SkyRainWind  阅读(14)  评论(0编辑  收藏  举报