2019ccpc江西省赛
A Cotree
题目链接
题意:给出n个点,仅有n-2条边,会形成两棵树,让你连一条边,求最小的。dis(i,j)代表对于i和j两个点路径上的边数。
思路:刚开始认为两颗树无论怎么连都不会影响答案。k队写了个树形DP+并查集,随便连了两天WA了。问了zl,发现肯定会影响。。zl得出连两颗树最为密集处,然后我尝试连了两棵树的重心,过了。
#include<bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e5 + 5; long long ans = 0; int son[maxn]; int n; int f[maxn]; struct edge{ int to,next; }; edge G[maxn<<1]; int head[maxn]; int edgeNum; int mx,rt; int Size; int sz[maxn]; void add_edge(int a,int b) { G[edgeNum].to=b; G[edgeNum].next=head[a]; head[a]=edgeNum++; } void dfsroot(int u,int fa){ sz[u]=1; int num=0; for(int i=head[u];i!=-1;i=G[i].next){ int v=G[i].to; if(v==fa) continue; dfsroot(v,u); sz[u]+=sz[v]; num=max(num,sz[v]); } num=max(num,Size-sz[u]); if(num<mx){ mx=num; rt=u; } } void init() { memset(head,-1,sizeof head); for (int i = 1; i <= n; i++)f[i] = i; } int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); } void mix(int x, int y) { int fx = find(x); int fy = find(y); f[fx] = fy; } void dfs(int x, int fa) { //cout << x << endl; son[x] = 1; for(int i=head[x];i!=-1;i=G[i].next){ int y=G[i].to; if (y == fa)continue; dfs(y, x); son[x] += son[y]; ans += 1ll * son[y] * (n - son[y]); } } int main() { scanf("%d", &n); init(); for (int i = 1; i < n - 1; i++) { int x, y; scanf("%d%d", &x, &y); add_edge(x,y); add_edge(y,x); mix(x, y); } int rt1 = find(1),rt2; int tot=0; for (int i = 1; i <= n; i++) { int fi=find(i); if (fi != rt1) { tot++; rt2=fi; } } Size=n-tot; mx=inf; dfsroot(rt1,-1); rt1=rt; Size=tot; mx=inf; dfsroot(rt2,-1); rt2=rt; add_edge(rt1,rt2); add_edge(rt2,rt1); dfs(1, -1); printf("%lld\n",ans); }
C Trap
题目链接
题意:给定n条可能存在重复的边,在边中任取四条,要求构成等腰四边形,且四边形满足互质。
思路:预处理互质数的表,预处理出现次数,n^2枚举上下底边情况,再二分查找满足条件的斜边个数。等腰梯形满足条件,三遍大于第四条边。
#include <bits/stdc++.h> #define maxn 10005 typedef long long ll; using namespace std; int n; int num[maxn]; vector <int>a,b,v[maxn]; void input(){ int i,x; for(i=0;i<n;i++) { scanf("%d",&x); a.push_back(x); num[x]++; } } void solve(){ sort(a.begin(),a.end()); a.erase(unique(a.begin(),a.end()),a.end()); for(int i=1;i<=10000;i++){ if(num[i]>=2){ b.push_back(i); } } for(int i=1;i<=10000;i++){ for(int j=0;j<b.size();j++){ if(__gcd(i,b[j])==1){ v[i].push_back(b[j]); } } } ll ans=0; for(int i=0;i<a.size();i++){ for(int j=i+1;j<a.size();j++){ int k=(a[j]-a[i])/2+1; int GCD=__gcd(a[i],a[j]); int pos=lower_bound(v[GCD].begin(),v[GCD].end(),k)-v[GCD].begin(); ans=ans+v[GCD].size()-pos; if(GCD==1){ if(num[a[i]]==2&&a[i]>=k)ans--; if(num[a[j]]==2&&a[j]>=k)ans--; } } } printf("%lld\n",ans); } int main(){ while(scanf("%d",&n)!=EOF){ a.clear(); b.clear(); for(int i=1;i<=10000;i++){ num[i]=0; v[i].clear(); } input(); solve(); } }
D Wave
题目链接
题意:对于给定数列,求一个数列满足,数列中至少两个元素,奇数位置都相同,偶数位置都相同,且奇数位置偶数位置值不同。求满足条件的最长子序列。
思路:想复杂了,k队的做法优化一下即可。枚举一个值作为奇数位置的值,将其之前的值省略,在奇数位置两两之间的的数都记录出现的次数。求最大出现次数即可。特判最后子序列长度为奇的情况。
#include <bits/stdc++.h> #define maxn 100005 using namespace std; int n, c; int a[maxn]; int num[105]; int vis[105]; int v[maxn]; int vcnt = 0; void input() { scanf("%d%d", &n, &c); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); } void solve() { int ans = 0; int u=0; int ANS; for (int t = 1; t <= c; t++) { int flag = 0; int cnt = 0; ans = 0; memset(num, 0, sizeof num); for (int i = 1; i <= n; i++) { if (a[i] == t) { flag = 1; cnt++; for (int j = 0; j < vcnt; j++) { vis[v[j]] = 0; } vcnt = 0; continue; } if (!flag) continue; if (!vis[a[i]]) { num[a[i]]++; vis[a[i]] = 1; v[vcnt++] = a[i]; } } for (int i = 1; i <= c; i++) { if (num[i] > ans) { ans = num[i]; u = i; } } flag = 1; //cout<<t <<' ' << ans << ' ' << u << endl; for (int i = n; i >= 1; i--) { if (a[i] == t) break; if (a[i] == u) flag = 0; } ANS = max(ANS,2 * ans + flag); //cout << ANS << endl; } printf("%d\n", ANS); } int main() { input(); solve(); }
F String
题目链接
题意:给出长度为n的序列,每次在n个字母中选择1个字母,求能构成avin字符串的几率
思路:水
#include <bits/stdc++.h> #define maxn 105 typedef long long ll; using namespace std; char a[maxn]; int gcd(int x, int y){ int z = x % y; while(z){ x = y; y = z; z = x % y; } return y; } int main(){ int n; int num[4]={0}; while(scanf("%d",&n)!=EOF){ memset(num,0,sizeof num); scanf("%s",a); for(int i=0;i<strlen(a);i++){ if(a[i]=='a') num[0]++; else if(a[i]=='v') num[1]++; else if(a[i]=='i') num[2]++; else if(a[i]=='n') num[3]++; } ll fm=pow(n,4); ll fz=num[0]*num[1]*num[2]*num[3]; if(fz==0) { printf("0/1\n"); continue; } ll GCD=gcd(fm,fz); fm=fm/GCD; fz=fz/GCD; printf("%lld/%lld\n",fz,fm); } return 0; }
G Traffic
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<vector> #include<set> #include<queue> #include<algorithm> #include<string> #include<cmath> #include<stack> #include<functional> #include<bitset> #include<unordered_map> #define ll long long #define maxn 100002 const int INF = 0x3f3f3f3f; using namespace std; int east[1002], north[1002]; int main(void){ int n, m, ans, i, flag; while(scanf("%d %d",&m,&n)!=EOF){ ans = 0; for(i = 0;i < m;i++){ scanf("%d",&east[i]); } for(i = 0;i < n;i++){ scanf("%d",&north[i]); } while(1){ flag = 1; unordered_map<int,int> mp; for(i = 0;i < m;i++){ mp[east[i]]++; } for(i = 0;i < n;i++){ mp[north[i] + ans]++; } unordered_map<int,int>::iterator iter; for(iter = mp.begin();iter != mp.end();iter++){ if(iter->second > 1){ flag = 0; break; } } if(flag){ printf("%d\n",ans); break; } ans++; } } return 0; }
H Rng
题目链接
题意:对于[1,n]的区间先选择一个区间[l1,r1],再选择一个区间[l2,r2]且满足r2<r1。求两个区间相交的概率
思路:概率打表找规律
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<vector> #include<set> #include<queue> #include<algorithm> #include<string> #include<cmath> #include<stack> #include<functional> #include<bitset> #define ll long long #define maxn 100002 const int INF = 0x3f3f3f3f; using namespace std; const int mod = 1e9 + 7; ll qpow(ll x,ll y){ ll res = 1; while(y){ if(y & 1){ res = res * x % mod; } x = x * x % mod; y >>= 1; } return res; } int main(void){ ll n; while(scanf("%lld",&n)!=EOF){ printf("%lld\n",(n + 1) * n / 2 % mod * qpow(n * n % mod,mod - 2) % mod); } return 0; }
I Budget
题目链接
题意:给出n个数,求n个数四舍五入之后的赚或者亏了多少
思路:水
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<vector> #include<set> #include<queue> #include<algorithm> #include<string> #include<cmath> #include<stack> #include<functional> #include<bitset> #include<unordered_map> #define ll long long #define maxn 100002 const int INF = 0x3f3f3f3f; using namespace std; char ch[52]; int main(void){ int n, i, sum, len; double ans; while(scanf("%d",&n)!=EOF){ sum = 0; for(i = 0;i < n;i++){ scanf("%s",ch); len = strlen(ch); if(ch[len - 1] >= '5'){ sum += 10 - ch[len - 1] + '0'; } else{ sum -= ch[len - 1] - '0'; } } ans = sum / 1000.0; printf("%.3f\n",ans); } return 0; }
J Worker
题目链接
题意:n个房间,有m个工作者,每个房间工作者工作ai时间,求一种分配方案使得每个房间工作者工作时间总和相同。
思路:求最小公倍数,题目中1018应该是1e18,需开long long
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<vector> #include<set> #include<queue> #include<algorithm> #include<string> #include<cmath> #include<stack> #include<functional> #include<bitset> #define ll long long #define maxn 100002 const int INF = 0x3f3f3f3f; using namespace std; ll gcd(ll x, ll y){ ll z = x % y; while(z){ x = y; y = z; z = x % y; } return y; } ll lcm(ll x, ll y){ return x / gcd(x,y) * y; } ll num[1202]; int main(void){ ll n, m, i, temp, sum; while(scanf("%lld %lld",&n,&m)!=EOF){ for(i = 0;i < n;i++){ scanf("%lld",&num[i]); } if(n == 1){ puts("Yes"); printf("%lld\n",m); } else{ temp = lcm(num[0],num[1]); for(i = 2;i < n;i++){ temp = lcm(temp,num[i]); } sum = 0; for(i = 0;i < n;i++){ sum += temp / num[i]; } if(m % sum){ puts("No"); } else{ puts("Yes"); for(i = 0;i < n;i++){ if(i){ printf(" "); } printf("%lld",temp / num[i] * m / sum); } puts(""); } } } return 0; }
K Class
#include<bits/stdc++.h> using namespace std; const int maxn = 7e3 + 5; int main() { int x, y; scanf("%d%d", &x, &y); int a = (x + y) / 2; int b = a - y; cout << a * b << endl; }