首页 > 其他分享 >2021 CCPC 桂林 ADEGIK

2021 CCPC 桂林 ADEGIK

时间:2023-10-10 20:57:31浏览次数:52  
标签:idx int ADEGIK CCPC long -- num 2021 dis

2021 CCPC 桂林 ADEGIK

https://codeforces.com/gym/103409
女队vp。就做了四道比较签到的题,后续补了两题,感觉比较考察思维。本身的代码不难写。其中,D题要能明白那个贪心的思想,尽量把大的放在前面,并且要知道怎么才能把大的放在前面!!!K题非常神奇,想了半天但其实是直接在边权为1的最短路的基础上dfs每一条路求最小值。

A Hero Named Magnus (签到)

签到,记得开long long

#include <bits/stdc++.h>
#define ll long long

using namespace std;

void solve () {
    ll n;
    cin >> n;
    cout << 2ll * n - 1 << endl;
}

int main () {
    int t;
    cin >> t;
    while (t--) solve ();
}

D. Assumption is All You Need (贪心)

题解思路:

我的丑丑示意图:

其实就是贪心思想,想要把大的数尽可能留在前面,所以就要按照左边吧的策略来交换,这样大的数最多会后移一位,不会对后面的交换造成更大影响。否则直接把大的一步换过去只会更劣。

个人觉得还是思维量不够,其实放cf上并不是一个多难的题,还是要多训!!

(这题cincout会超时)

#include <bits/stdc++.h>
#define ll long long

using namespace std;
typedef pair<int, int> pii;
const int N = 2025;
int n, a[N], b[N];

void solve () {
    vector<pii> v;
	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]);
    for (int i = 1; i <= n; i++) {
        if (a[i] == b[i])   continue;
        if (a[i] < b[i]) {
            printf ("-1\n");
            return ;
        }
        while (a[i] != b[i]) {
            for (int j = i + 1; j <= n; j++) {
                if (a[j] < a[i] && a[j] >= b[i]) {
                    swap (a[i], a[j]);
                    v.push_back ({i, j});
                }
            }
        }
    }
    printf ("%d\n", v.size ());
    for (auto i : v)    printf ("%d %d\n", i.first, i.second);
}

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

E. Buy and Delete (求最小环)

如果一条边也选不了就0步。
否则就是找最小的环,如果能构造出来就两步,否则一步
求最小环的方法,每个点出发求一遍最短路,然后在回到起点的时候记录环的长度,综合求一个最小值。

#include <bits/stdc++.h>
#define ll long long

using namespace std;
typedef pair<int, int> pii;
const int N = 2005, M = 5005;
int h[N], e[M], ne[M], w[M], idx;
int dis[N], n, m, k, minn = 1e6;
bool vis[N];

void add (int a, int b, int c) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}

int dijkstra(int st) {
    memset (dis, 0x3f, sizeof dis);
    memset (vis, false, sizeof vis);
    dis[1] = 0;
    priority_queue<pii, vector<pii>, greater<pii>>q;
    q.push({0, st});//dis num

    int sum = 1e9 + 5;
    while (!q.empty()){
        auto t = q.top();
        q.pop();
        int num = t.second, distance = t.first;
        if (vis[num])    continue;//pass
        vis[num] = true;

        for (int i = h[num]; i != -1; i = ne[i]){
            int j = e[i];
            if (j == st)    sum = min (sum, distance + w[i]);
            if (dis[j] > distance + w[i]){
                dis[j] = distance + w[i];
                q.push({dis[j], j});
            }
        }
    }
    return sum;
}

int main () {
    memset (h, -1, sizeof h);
    scanf ("%d%d%d", &n, &m, &k);
    while (m--) {
        int a, b, c;
        scanf ("%d%d%d", &a, &b, &c);
        add (a, b, c);
        minn = min (minn, c);
    }
    if (minn > k) {
        printf ("0");
        return 0;
    }
    int sum = 1e9 + 5;
    for (int i = 1; i <= n; i++) {
        //if (vis[i]) continue;
        sum = min (sum, dijkstra (i));
    }
    //cout << sum << endl;
    if (sum <= k)   printf ("2");
    else    printf ("1");
}

G. Occupy the Cities (二分)

这是我想的,二分最少时间

check的方法就是:假设当前要 check \(x\),用变量 \(l\) 来记录碰到 \(1\) 之前的连续 \(0\) 个数,如果再碰到 \(1\) 之前 \(l > x\),则 return false

在遇到 \(1\) 时又分为两种情况,一种是之前已经有一个 \(1\) (能影响左边的 \(l\) 个 \(0\) 了),那么可以把 \(l\) 清空。若之前没有 \(1\),那么表示之前是 \(0...01\) 的形式,标记一下已经遇到了一个 \(1\),这里用 \(find=1\) 表示遇到了 \(1\)。接着往后统计碰到 \(1\) 之后的连续 \(0\) 的数量 \(r\)。
\(r==x-1\) 时:若 \(l==x\),这一段 \(1\) 就需要 \(x\) 天才能把左右的 \(0\) 给覆盖,从这开始断开,接着统计下一段
\(r==x\) 时:若 \(l<x\) 这一段 \(1\) 就需要 \(x\) 天才能把左右的 \(0\) 给覆盖,从这开始断开,接着统计下一段;否则 \(l==x\),那么 这个 \(1\) 需要 \(x+1\) 天才能把左右长都为 \(x\) 的 \(0\) 给覆盖掉(其实这个会在 \(r==x-1\) 的情况中给判掉)

就按照上述去 \(check\),如果最后还剩下 \(0\) 没消掉,那么就是不合法的。注意中间变量置 \(0\) 的小细节。

#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
int n;
string s;

bool check (int x) {
	//cout << x << endl;
	int l = 0, r = 0, find = 0;
	for (int i = 1; i <= n; i++) {
		if (s[i] == '0') {
			if (find)	r++;
			else	l++;
		}
		else {
			if (find)	l = r = 0;
			else	find = 1;
		}
		if (l > x)	return false;
		
		if (find && r == x - 1) {
			if (l == x)	l = r = find = 0;
		}
		if (find && r == x) {
			if (l < x)	l = r = find = 0;
			else	return false;
		}
		//cout << l << ' ' << r <<' ' <<find <<endl;
	}
	if (l && !find)	return false;
	return true;
}

void solve () {
	cin >> n >> s;
	int cnt = 0;
	for (int i = 0; i <n; i++)	cnt += (s[i] == '0');
	if (cnt == 0) {
		cout << "0\n";
		return ;
	}
	s = ' ' + s;
	int l = 1, r = n;
	while (l < r) {
		int mid = l + r >> 1;
		if (check (mid))	r = mid;
		else	l = mid + 1;
	}
	cout << r << endl;
}

signed main() {
   ios::sync_with_stdio(false);
   cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while (t--) {
    	solve (); 
	} 
     
}
/*
5
15
010000010000010
8
10000100
9
100001000
10
1000010000
11
00010001000
*/

I. PTSD (贪心)

小贪心。从后往前用0,1来抵,如果当前数后面有多余的0,1就可选,否则选不上。

#include <bits/stdc++.h>
#define ll long long

using namespace std;
int n;
string s;

void solve () {
    cin >> n >> s;
    s = ' ' + s;
    ll c1 = 0, c0 = 0, ans = 0;
    for (int i = n; i >= 1; i--) {
        if (s[i] == '0') c0++;
        else {
            if (c0) ans += i, c0--;
            else if (c1)    ans += i, c1--;
            else    c1++;
        }
    }
    cout << ans << endl;
}

int main () {
    int t;
    cin >> t;
    while (t--) solve ();
}

K. Tax (bfs + dfs)

神秘题,本质就是大暴力,在边权为1的图上跑最短路,这样保证了不会绕路(走重复的某条边),即走这样的路一定是最优的,然后在最短路的基础上dfs每一条边算最短路即可,复杂度不会算,总之很神奇。

#include <bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> PII;
const int N = 55, M = N * N;
int h[N], e[M], ne[M], w[M], idx;
int n, m, v[M], dis[N], ans[N], cnt[M];
bool vis[N];

void add (int a, int b, int c) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}

void dijkstra(){
    memset (dis, 0x3f, sizeof dis);
    dis[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>>q;
    q.push({0, 1});//dis num

    while (!q.empty()){
        auto t = q.top();
        q.pop();
        int num = t.second, distance = t.first;
        if (vis[num])    continue;//pass
        vis[num] = true;

        for (int i = h[num]; ~i; i = ne[i]){
            int j = e[i];
            if (dis[j] > distance + 1){ //视作边权为1
                dis[j] = distance + 1;
                q.push({dis[j], j});
            }
        }
    }
}

void dfs (int u, int sum) {
    ans[u] = min (ans[u], sum);
    for (int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if (dis[j] == dis[u] + 1) {
            cnt[w[i]]++;
            dfs (j, sum + cnt[w[i]] * v[w[i]]);
            cnt[w[i]]--;
        }
    }
}

signed main () {
    memset (h, -1, sizeof h);
    scanf ("%lld%lld", &n, &m);
    for (int i = 1; i <= m; i++)    scanf ("%lld", &v[i]);
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        scanf ("%lld%lld%lld", &a, &b, &c);
        add (a, b, c), add (b, a, c);
    }
    dijkstra ();
    //for (int i = 2; i <= n; i++)    printf ("%d\n", dis[i]);
    memset (ans, 0x3f, sizeof ans);
    dfs (1, 0);
    for (int i = 2; i <= n; i++)    printf ("%lld\n", ans[i]);
}

B题set维护不太会写,J后缀树也不会www

标签:idx,int,ADEGIK,CCPC,long,--,num,2021,dis
From: https://www.cnblogs.com/CTing/p/17754509.html

相关文章

  • THUPC2021 鬼街
    Day\(\text{M}_r(\text{O}_2)\)。这东西原来叫减半报警器??首先这题肯定和数论没啥关系,因为\(10^5\)之内的\(\max\omega(n)=6\),即一个数至多只有\(6\)个质因子。然后我们发现如果\(x\)有\(k\)个不同的质因子,这\(k\)个质因子代表的房子内闹鬼总次数达到了\(y\),那么......
  • April Fools Day Contest 2021 A. Is it rated - 2
    询问若干个问题,每个问题用一段字符串表示,存在空格。每个问题一行,对于每个回答,只需要输出\(NO\)。view1#include<bits/stdc++.h>chars[1000005];voidsolve(){ while(fgets(s,1000005,stdin)!=NULL){ std::cout<<"NO"<<std::endl;//fgets从流中读取,读取失......
  • 2021-2022 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2021) gym 104670
    原题容易想到最短路DAG求出来,起初我以为要求最小割,但这是错误的,因为可能有多条边联通了一个点的情况,这时候选择最小割不一定是最优的我们猜想一个思路:答案一定是包含\(1\)号节点的连通块全部填\(N\),剩下的填\(S\)。发现在最短路DAG中,\(1\rightarrown\)的所有路径......
  • [UOJ618]【JOISC2021】聚会 2
    #618.【JOISC2021】聚会2就是相当于选中的点在整棵树上的重心首先,当\(i\)为奇数时,答案为\(1\)当\(i\)为偶数时,可以将选中的点分为两个子树,分别记其根节点为\(x\)和\(y\)那么可以发现,所以合法的\(x\)和\(y\)构成一个连通块,那么当前答案就是连通块的直径,且随着\(i\)的增大,连通......
  • P7928 [COCI2021-2022#1] Kamenčići
    P7928[COCI2021-2022#1]Kamenčići[P7928COCI2021-2022#1]Kamenčići-洛谷|计算机科学教育新生态(luogu.com.cn)目录P7928[COCI2021-2022#1]Kamenčići题目大意思路code题目大意Alice和Bob又在玩游戏。在他们面前有\(n\)块石头排成一行,石头有红和蓝两种颜......
  • P8511 [Ynoi Easy Round 2021] TEST_68
    题目传送门看到异或最大值,根据套路不妨考虑\(0-1trie\)。通过\(trie\)找到异或值最大的点对\((x,y)\)。那么除了\((x,y)\)到\(1\)路径上的点之外,其他的点的答案就是\((x,y)\)的异或值。接下来考虑怎么算出这\((x,y)\)到\(1\)路径上的点的答案,可以直接暴力计算!......
  • [鹤城杯 2021]New MISC
    [鹤城杯2021]NewMISC拿到文件发现是PDF打开文件,完全看不懂。用010打开后发现有一段中0920出现次数比较多,大概率为wbStego4open加密,上家伙使用工具wbStego4.3open进行解密最后一直点继续就行。......
  • 2022 China Collegiate Programming Contest (CCPC) Mianyang Onsite
    2022ChinaCollegiateProgrammingContest(CCPC)MianyangOnsiteC.CatchYouCatchMe解题思路:站在距离出口最近的点等深度深的蝴蝶飞上来即可。时间复杂度:\(O(n)\)代码:#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;voidsolve(){ intn......
  • 【主席树】P8201 [传智杯 #4 决赛] [yLOI2021] 生活在树上(hard version)题解
    P8201简单题。题中求的是\(dis_{a,t}\oplusdis_{t,b}=k\)是否存在,显然不好直接维护,考虑转化。令\(dist=dis_{a,t}\oplusdis_{t,b}\),\(val=\bigoplus\limits_{x\in\text{path}(a,b)}w_x\)。如果\(t\)在\(\text{path}(a,b)\)上,则\(dist=val\oplus......
  • 2022 China Collegiate Programming Contest (CCPC) Weihai Site EAJGCI
    2022ChinaCollegiateProgrammingContest(CCPC)WeihaiSite目录2022ChinaCollegiateProgrammingContest(CCPC)WeihaiSiteVP概况E-PythonWillbeFasterthanC++A-DunaiJ-Eat,Sleep,RepeatG-Grade2C-GrassI-DragonBloodlineVP概况这场我一年......