Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2)
Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2)
题目链接:Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2)
A题题解
- 题意
- 题意是给你一串整数,,要找到一个除数使得每一个数被除后正数的个数大于等于 ⌈n2⌉⌈n2⌉,,,
- 分析
- 统计出所有正数,负数的个数,,正数多那个除数就是1,负数多就是-1
- AC代码
/* author:Agnel_Cynthia theme:思维 */ #include<bits/stdc++.h> using namespace std; typedef long long ll; //fgets getline # define IOS ios::sync_with_stdio(false); cin.tie(0);cout.tie(0) //set<int> s; ll mod = 1e9 + 7; int main(){ IOS; int n; cin >> n; ll sum ; if(n % 2== 0) sum = n / 2; else sum = n / 2 + 1; int a= 0 , b = 0; for(int i =0 ; i < n ; i ++){ int x ; cin >> x; if(x > 0) a ++; else if(x < 0) b++; } if(a >= sum) cout << 1 << endl; else if(b >= sum) cout << -1 << endl; else cout << 0 << endl; return 0; }
B题题解
- 题意
- 两个人买蛋糕,蛋糕一层比一层小,规定先买小,再买大,即先买1,再买2,...最后买n
- 有2n家店,每家店都是只出售一个等级蛋糕的一个,相邻蛋糕店的距离为1,
- 两人刚开始都在最左边,问两个人最少走多长距离可以买好两个蛋糕
- 解析
- 只要比较第一次出现的1~n层,和第二次的1~n层,分别计算求和,用vector方便计算
- 注意sum可能大于int,要用ll
- AC代码
/* author:Agnel_Cynthia theme:模拟 */ #include<bits/stdc++.h> using namespace std; typedef long long ll; //fgets getline # define IOS ios::sync_with_stdio(false); cin.tie(0);cout.tie(0) //set<int> s; ll mod = 1e9 + 7; int a[200000],b[200000]; int main(){ IOS; int n; cin >> n; for(int i = 1; i <= 2 *n; i ++){ int x; cin >> x ; if(a[x]==0) a[x] = i ; else b[x] = i; // cout << b[x] << endl; } // for(int i = n + 1; i <= 2 * n; i ++){ // int x; // cin >> x ; // b[x] = i ; // } ll sum = 0; a[0] = 1, b[0] = 1; for(int i = 0; i < n ; i++){ // cout << a[i] <<endl; sum += abs(a[i+1] - a[i]); } //cout <<sum ; for(int i = 0; i < n ; i++){ sum += abs(b[i+1] - b[i]); } cout << sum << endl; return 0; }
C题题解
- 题意:
- 给两个位置A(a,b),B(c,d),需要从A到B,图中有一些水路,不能走水,但可以建隧道
- 隧道成本为:(rs−rt)^2+(cs−ct)^2 (rs,cs),(rt,ct)分别为隧道两端,问最小的从建隧道的最小成本
- 解析:
- 数据量很小,我们考研暴力做
- 用深搜或者广搜寻找变通块,遍历A连通块和B连通块的建桥成本,找最小的成本
- AC代码
/* author:Agnel_Cynthia theme:暴力,搜索 */ #include<bits/stdc++.h> using namespace std; typedef long long ll; //fgets getline # define IOS ios::sync_with_stdio(false); cin.tie(0);cout.tie(0) //set<int> s; ll mod = 1e9 + 7; int n ; //int a[400000]; char mp[55][55]; int vis[55][55]; struct note { int x,y; }mp1[55 * 55],mp2[55 * 55]; int tx[4] = {0,1,0,-1}; int ty[4] = {1,0,-1,0}; int cnta = 1,cntb = 1; void dfs1(int x , int y){ for (int i = 0; i < 4; ++i) { int dx = x + tx[i]; int dy = y + ty[i]; /* code */ if(dx >= 0 && dx <= n-1 && dy >= 0 && dy < n){ if(mp[dx][dy]=='0' && !vis[dx][dy]) { mp1[cnta].x = dx; mp1[cnta].y = dy; cnta++; vis[dx][dy] = 1; dfs1(dx,dy); } } } } void dfs2(int x ,int y){ for(int i = 0; i < 4 ; i++){ int fx = x + tx[i]; int fy = y + ty[i]; if(fx >= 0 && fx < n && fy >= 0 && fy < n){ if(mp[fx][fy] == '0' && !vis[fx][fy]){ mp2[cntb].x = fx; mp2[cntb].y = fy; cntb++; vis[fx][fy] = 1; dfs2(fx,fy); } } } } int main(){ IOS; //int n; cin >> n; int a , b ,c ,d; cin >> a >> b >> c >> d; for(int i = 0 ; i < n ; i++){ cin >> mp[i]; } mp1[0].x = a - 1,mp1[0].y = b - 1; mp2[0].x = c - 1,mp2[0].y = d - 1; dfs1(a-1,b-1); memset(vis,0,sizeof(vis)); dfs2(c-1,d-1); int maxn = 999999999; for(int i = 0; i < cnta; i++) for(int j = 0; j < cntb; j ++){ maxn = min(maxn,(mp1[i].x - mp2[j].x) * (mp1[i].x - mp2[j].x) + (mp1[i].y - mp2[j].y) * (mp1[i].y - mp2[j].y)); } cout << maxn << endl; return 0; }
D题题解
- 题意:
- 有一条环形火车线路,有n个站,火车只能从a站到a+1站,或者从n到1(环形)
- 有m个需求,需要从a运送一个糖果到b
- 每次经过一个火车站只能装一个糖果
- 问最少走多少路可以装运完所有糖果(起点1~n,输出n个结果)
- 解析:
- 一个时间在同一火车站,只能装1个糖果,呢么在a站有k个糖果需要装,我们必须让火车循环k-1次
- 最后一次只要到终点就完成,最后一次是从a出发的运送路线最短的dis(i,e)
- 我们找到最多起始的站,呢么别的运算路线都可以在k-1中分别完成,呢么结果就是maxcnt(i)*n+dis(s,i)+dis(i,e)
- 如果有多个起始站的站,呢么选择最大的dis(s,i)+dis(i,e),这样才能把所有的需要全部包含进去
- AC代码
/* author:Agnel_Cynthia theme:模拟 */ #include<bits/stdc++.h> using namespace std; typedef long long ll; //fgets getline # define IOS ios::sync_with_stdio(false); cin.tie(0);cout.tie(0) //set<int> s; ll mod = 1e9 + 7; int cnt[100005],mind[100005]; int dis(int a,int b,int n){ if(a > b) return n - a + b; else return b - a; } int main(){ IOS; int n,m,a,b; cin >> n >> m; int maxa,maxb; for(int i = 0; i <= n ; i++){ mind[i] = 9999999; } for(int i = 0; i < m; i ++){ cin>> a >> b; cnt[a]++; mind[a] = min(mind[a],dis(a,b,n)); } for(int i = 1; i <= n ; i++){ ll ans = 0; for(int j = 1 ; j <= n ; j++){ if(cnt[j] == 0) continue ; ans = max(ans , (ll) (cnt[j] - 1) * n + mind[j] + dis(i,j,n)); } cout << ans << " "; } }
E题题解
- 解析:
- 构造题
- 官方题解:
- 第一个数放-1,后面长为len,和为sum,每个都不为负数
- k=(sum−1)(len+1)−sum⋅len=sum−len−1
- 随便代入一个len,构造输出,因为|ai|≤10^6,len>1000
- AC代码
#include<bits/stdc++.h> #define ll long long #define MAXN 2005*2 using namespace std; void print(int k,int n) { printf("-1 "); for(int i=0;i<k;i++) { if(n>=1000000) { printf("1000000 "); n=n-1000000; } else { printf("%d ",n); n=0; } } } int main() { ll n; cin>>n; printf("2000\n"); int k=1999; n=k+1+n; print(k,n); }
- 题意
- 一个数列求出最大的 区间和乘以区间长度,
- 他给的算法当前面一段区间和出现负数就舍弃了,没有考虑长度对最后答案的影响,
- 题目要我们构造一个数列,,使得这个数列的正确答案比它的做法算出的结果大k
- 分析
- 可以构造一个前面1998个都是0,后面一个数是-p,一个时p + q,
- 这样正确的答案就是 2000q2000q,他算出的答案就是 p+qp+q,
- 要大k,就是 2000q−(p+q)=k2000q−(p+q)=k,也就是 q=p+k1999q=p+k1999 ,为了保证p,q都是整数,那么就设 p=1999−k%1999p=1999−k%1999,这样算出的q就是整数,
- AC代码
/* author:Agnel_Cynthia theme:思维,构造 */ #include<bits/stdc++.h> using namespace std; typedef long long ll; //fgets getline # define IOS ios::sync_with_stdio(false); cin.tie(0);cout.tie(0) //set<int> s; ll mod = 1e9 + 7; int main(){ IOS; int k; cin >> k; cout << 2000 << endl; for(int i = 1; i <= 1998; i++) cout << 0 << " "; //这样就可以保证p为 整数 ,减去多余的余数 int q = 1999 - k % 1999; int p = (q+k) / 1999; //cout << q << " " << p ; cout << -q << " " << p + q << endl; return 0; }