7.13 2020牛客暑期多校訓練營(第二場)題解及補題
目錄
7.13 2020牛客暑期多校訓練營(第二場)題解及補題
比賽過程
D題是簽到題,後面做C和H,實在有點可惜,方法使用錯誤超時結束。C應該正確使用dfs序,H選取右小角的6*6區域暴力。
題解
B Boundary
題意
給定n個點,讓你找最多有多少個點共圓並且該圓過原點。
解法
用求三角形外心的模板。遍歷選取兩個點和原點組成三角形,求三角形的外心並將點存起來,找出被覆蓋最多次數的點即為圓心,是在圓上的點組成的多邊形的邊數,得到邊數後求(int)sqrt(ans*2) +1就是答案。
程式碼
#include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <deque> #include <exception> #include <fstream> #include <functional> #include <limits> #include <list> #include <map> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stack> #include <stdexcept> #include <streambuf> #include <string> #include <utility> #include <vector> #include <cwchar> #include <cwctype> using namespace std; #define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) const int inf = 0x3f3f3f3f; typedef long long ll; const int maxn = 2000500; const ll mod = 1e9 + 7; typedef pair<int,int> pii; const double pi = acos(-1); typedef long long ll; typedef pair<double, double> pdd; const int N = 2005; struct point { ll x, y; }a[N]; vector<pdd> v; //求三角形外心 void getc(const point& p1, const point& p2, const point& p3, pdd& center) { ll x1 = p1.x; ll x2 = p2.x; ll x3 = p3.x; ll y1 = p1.y; ll y2 = p2.y; ll y3 = p3.y; ll t1=x1*x1+y1*y1; ll t2=x2*x2+y2*y2; ll t3=x3*x3+y3*y3; double temp=x1*y2+x2*y3+x3*y1-x1*y3-x2*y1-x3*y2; center.first = double(t2*y3+t1*y2+t3*y1-t2*y1-t3*y2-t1*y3)/temp; center.second = double(t3*x2+t2*x1+t1*x3-t1*x2-t2*x3-t3*x1)/temp; } int main() { IO; int n; cin>>n; for(int i = 1; i <= n; ++ i) cin>>a[i].x>>a[i].y; point temp; temp.x = 0, temp.y = 0; for(int i = 1; i <= n; ++ i) { for(int j = i + 1; j <= n; ++ j) { pdd c; if(a[i].x * a[j].y != a[i].y * a[j].x) { getc(a[i], a[j], temp, c); v.push_back(c); } } } sort(v.begin(),v.end()); int ans = 0, cnt = 0; pdd tmp = v[0]; for(auto i: v) { if(i == tmp) { cnt++; } else { ans = max(ans, cnt); cnt = 1; tmp = i; } } ans = max(cnt, ans); cout<<int(sqrt(ans*2))+1; return 0; }
C Cover the Tree
題意
題目給了一個無根樹,要求找到最小數量的鏈,使得樹上任意一個邊至少被一個鏈包含,
輸出鏈的最小數目ans,以及每一個鏈的第一個結點以及最後一個結點。
解法
要求找最小數目的鏈包含所有的邊,貪心的思想肯定是找兩端是葉子節點的鏈,那麼統計一下葉子節點的數目cnt,如果是奇數個葉子結點,那麼ans就是(cnt+1)/2,如果是偶數個葉子節點,那麼ans就是cnt/2。
n<=2的時候答案顯然,n>=3的時候,取任意一個非葉子節點作為根(這裡我們選取了度數最多的點作為根),然後跑葉子節點的dfs序,那麼假設cnt為偶數,我們構造的cnt/2條鏈就是l1-lcnt/2+1,l2-lcnt/2+2,……,lcnt/2-lcnt,如果cnt為奇數,那麼只需要把最後一個剩下的葉子節點和根節點連線即可。
程式碼
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
vector<int> g[200010];
int dfs[200020];//dfs序 陣列
int len,tim;// len 是當前dfs序的長度, tim 是時間
int s[200020],e[200020];// 存的某點子樹對應區間的起點 和終點, 標號i表示某點dfs序中的位置
int pos[200020];//某點i的 dfs序位置
int d[200020];
void DFS(int u,int fa)
{
int x=len+1;
if(d[u]==1){
s[++len]=++tim;// 起點是開始時間
dfs[len]=u;
pos[u]=len;
}
int sz=g[u].size();
for(int i=0;i<sz;i++)
{
if(g[u][i]!=fa)//不能dfs遍歷父親
{
DFS(g[u][i],u);
}
}
e[x]=tim;// 結束時間 即為以他為子樹的終止區間
}
int main(){
scanf("%d",&n);
int m=n-1;
memset(d,0,sizeof(d));
int st=-1,stt=0;
for(int i=1;i<=m;i++){
int l,r;
scanf("%d%d",&l,&r);
g[l].push_back(r);
g[r].push_back(l);
d[l]++;
d[r]++;
if(d[l]>stt){
stt=d[l];
st=l;
}
if(d[r]>stt){
stt=d[r];
st=r;
}
}
DFS(st,0);
cout<<(len+1)/2<<endl;
if(len&1){
for(int i=1;i<=len/2;i++){
cout<<dfs[i]<<" "<<dfs[i+len/2]<<endl;
}
cout<<st<<" "<<dfs[len]<<endl;
}
else{
for(int i=1;i<=len/2;i++){
cout<<dfs[i]<<" "<<dfs[i+len/2]<<endl;
}
}
}
D Duration
題意
題目給了同一天中的兩個時間點,格式為HH:MM:SS,然後要求輸出兩個時間點之間的秒數。
解法
簽到題,只需要稍微計算一下即可。
程式碼
#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(0), cin.tie(0)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int inf = ~0u >> 1;
typedef pair<int,int> P;
#define REP(i, a, n) for (int i = a; i < (n); ++i)
#define PER(i, a, n) for (int i = (n) - 1; i >= a; --i)
int main() {
IO;
int h1, h2, m1, m2, s1, s2;
scanf("%d:%d:%d", &h1, &m1, &s1);
scanf("%d:%d:%d", &h2, &m2, &s2);
int sum1 = h1 * 3600 + m1 * 60 + s1;
int sum2 = h2 * 3600 + m2 * 60 + s2;
int ans = abs(sum1 - sum2);
cout << ans << endl;
return 0;
}
F Fake Maxpooling
題意
題目給了一個nm的矩陣,矩陣中Ai,j=lcm(i,j),然後題目要輸輸出所有KK的子矩陣的最大值之和。
解法
首先跑一下nm的矩陣,然後當k<=6的時候用純暴力即可,k>=7的時候,我們只需要貪心的尋找每一個KK的子矩陣的右下角的6*6的小矩陣求最大值即可。
程式碼
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 5005
ll n,m,k;
ll a[maxn][maxn];
ll gcd(ll b,ll c){return c==0?b:gcd(c,b%c);}
ll lcm(ll b,ll c){return b * c/ gcd(b, c);}
int main(){
scanf("%lld%lld%lld",&n,&m,&k);
for(ll i=1;i<=5000;i++){
for(ll j=i;j<=5000;j++){
a[i][j]=lcm(i,j);
a[j][i]=a[i][j];
}
}
ll ans=0;
if(k<=6){
for(ll i=0;i<=n-k;i++){
for(ll j=0;j<=m-k;j++){
ll tmp=0;
for(int w=1;w<=k;w++){
for(int e=1;e<=k;e++){
tmp=max(tmp,a[i+w][j+e]);
}
}
ans+=tmp;;
}
}
}else{
int l=-1,r=-1;
for(ll i=0;i<=n-k;i++){
for(ll j=0;j<=m-k;j++){
ll tmp=0;
for(int w=k-5;w<=k;w++){
for(int e=k-5;e<=k;e++){
tmp=max(tmp,a[i+w][j+e]);
}
}
ans+=tmp;;
}
}
}
cout<<ans<<endl;
}
J Just Shuffle
題意
對於一個排列A,給定一個置換規則P,在使用置換P K 次後得到新的排列B
解法
(置換群概念理解為博主Yoangh原創內容:連結)
首先給你一個序列,假如:
s = {1 2 3 4 5 6}
然後給你一個變換規則
t = {6 3 4 2 1 5}
就是每一次按照t規則變換下去
比如這樣
第一次:6 3 4 2 1 5
第二次:5 4 2 3 6 1
第三次:1 2 3 4 5 6
發現經過幾次會變換回去,在變換下去就是迴圈的了,這就是一個置換群。
我們可以這樣表示一個置換群,比如按照上面變化規則
1->6->5->1 那麼這些是一個輪換
2->3->4->2 這些是一個輪換
所以可以寫為
t = { {1 6 5},{ 2 3 4 } }
解法:
A ^ K = B
且P等於A再置換一次
我們設Z為K的逆元,r為置換迴圈節,則 B ^ Z = A
//逆元定義如下:
Z * K % r == 0 ,(r為置換迴圈節)
令Z:Z * K % r == 1
求出Z,然後讓B置換Z次即可得A。
程式碼
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
using namespace std;
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int inf = 0x3f3f3f3f;
typedef long long ll;
const int maxn = 2000500;
const ll mod = 1e9 + 7;
typedef pair<int,int> pii;
const double pi = acos(-1);
typedef long long ll;
const int N = 1e5 + 1;
int a[N], b[N], c[N];
vector <int > v;
void solve(int k)
{
int i, j;
int r = v.size(), inv;
for(i = 0; i < r; i ++)
if((ll)k * i % r == 1)
inv = i;
for(j = 0; j < r; j ++)
c[v[j]] = v[(j + inv) % r];
}
int main() {
IO;
int n, k;
cin>>n>>k;
for(int i = 1; i <= n; i ++)
cin>>b[i];
for(int i = 1; i <= n; i ++) {
if(!a[i]) {
v.clear();
int x = b[i];
while(!a[x]) {
a[x] = 1;
v.push_back(x);
x = b[x];
}
solve(k);
}
}
for(int i = 1; i <= n; i ++) {
if(i != n)
cout<<c[i]<<" ";
else
cout<<c[i]<<endl;
}
return 0;
}