2017-2018 ACM-ICPC Asia East Continent League Final (ECL-Final) 题解(10 / 13)
2017-2018 ACM-ICPC Asia East Continent League Final (ECL-Final)
9题金
6题银
5题铜
题目比较简单,但是读题太难了…
比赛链接:https://codeforces.com/gym/101775
最近时间比较紧,简单写一点题解吧,还有好多题没有补呜呜呜
这场读题太难了…
最后三题过的人太少了懒得补了…
目录
- A、Chat Group
- B、Scapegoat
- C、Traffic Light
- D、Mr. Panda and Geometric Sequence
- J、Straight Master
- H、Mr. Panda and Birthday Song
- K、Downgrade
- L、SOS
- M、World Cup
A、Chat Group
签到题
题目要求的是 Cnk+⋯+cnnC_n^k+\cdots+c_n^nCnk+⋯+cnn。
但是 n≤109n\le 10^9n≤109不直接枚举或者预处理,所以考虑反着做。
我们知道 Cn1+Cn2+⋯+Cnn=2nC_n^1+C_n^2+\cdots+C_n^n=2^nCn1+Cn2+⋯+Cnn=2n,所以答案就是 2n−(Cn0+Cn1+⋯+Cnk−1)2^n-(C_n^0+C_n^1+\cdots+C_n^{k-1})2n−(Cn0+Cn1+⋯+Cnk−1)
k≤105k\le 10^5k≤105 可以递推求组合数。因为要求的是Cn0∼Cnk−1C_n^0\sim C_n^{k-1}Cn0∼Cnk−1,所以我们可以直接递推求组合数。从 Cn0=1C_n^0=1Cn0=1 开始, Cnm=n−m+1m×Cnm−1C_n^m=\cfrac{n-m+1}{m}\times C_n^{m-1}Cnm=mn−m+1×Cnm−1。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
const int N = 500007, mod = 1e9 + 7;
const double PI = acos(-1);int n, m, t, k, kcase;int qpow(int a, int b)
{int res = 1;while(b) {if(b & 1) res = 1ll * res * a % mod;a = 1ll * a * a % mod;b >>= 1;}return res;
}int inv(int x)
{return qpow(x, mod - 2);
}int main()
{scanf("%d", &t);while(t -- ) {scanf("%d%d", &n, &k);if(k > n) {printf("Case #%d: 0\n", ++ kcase);continue;}ll ans = qpow(2, n) - 1;ll sum = 1;for(int i = 1; i <= k - 1; ++ i) {sum = 1ll * sum * 1ll * (n - i + 1) % mod * inv(i) % mod;ans = (ans - 1ll * sum % mod + mod) % mod;}printf("Case #%d: %lld\n", ++ kcase, ans);}return 0;
}
B、Scapegoat
Problem
现在某人闯祸了,产生了 N 个锅,每个锅有个严重点数,现在可以安排 M 个替罪羊去背锅。
每个替罪羊最多只能背一个锅。若一只羊背一个锅,则该锅的严重点数全部算在它头上;若多只羊背同一个锅,则每个羊分到该锅的一部分的严重点数。
现在考虑一种安排方案,使得所有的身上的严重点数的方差最小。
Solution
先考虑上 N 只羊一一对应地背 N 个锅,剩下 M−N 个替罪羊身上严重点数均为 0,当然这样并不是最优解。
应当把再剩下 M−N 个替罪羊安排进 N 个锅里分摊责任,使得方差减小。考虑贪心的思路,每次安排进去一只羊,都要使得方差减小最多。
考虑将新来的羊安排到某个任务,该任务严重点数为 a[i],且原来的背锅羊数是 num,那么首先每个替罪羊分到的严重点数的平均数肯定是不变的 X‾=a[1]+a[2]+⋯+a[n]m\overline{X} = \cfrac{a[1]+ a[2]+ \cdots + a[n]}{m}X=ma[1]+a[2]+⋯+a[n],,因此它原本对方差的贡献为 1m⋅num⋅(a[i]num−X‾)2\cfrac{1}{m} \cdot num \cdot (\cfrac{a[i]}{num}-\overline{X})^2m1⋅num⋅(numa[i]−X)2。
而现在新加进去一个替罪羊,这个任务对方差的新的贡献为 1m⋅(num+1)⋅(a[i]num+1−X‾)2\cfrac{1}{m} \cdot (num+1) \cdot (\cfrac{a[i]}{num+1}-\overline{X})^2m1⋅(num+1)⋅(num+1a[i]−X)2
显然,关键的差值就是 Δ=num⋅(a[i]num−X‾)2−(num+1)⋅(a[i]num+1−X‾)2=a[i]2num⋅(num+1)−X‾2\Delta = num \cdot (\cfrac{a[i]}{num}-\overline{X})^2 -(num+1) \cdot (\cfrac{a[i]}{num+1}-\overline{X})^2 = \cfrac{a[i]^2}{num \cdot (num+1)} - \overline{X}^2Δ=num⋅(numa[i]−X)2−(num+1)⋅(num+1a[i]−X)2=num⋅(num+1)a[i]2−X2,因此我们让每次挑一个任务让它的 Δ+X‾2=a[i]2num⋅(num+1)\Delta + \overline{X}^2 = \cfrac{a[i]^2}{num \cdot (num+1)}Δ+X2=num⋅(num+1)a[i]2 最大即可,直接使用优先队列维护即可。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
#include <queue>
using namespace std;
typedef long long ll;
typedef int itn;
const int N = 500007, mod = 1e9 + 7;
const double PI = acos(-1);
const double eps = 1e-8;int n, m, a[N], t;
int sum, kcase;
double avg;
struct node
{itn id, num;node(int _id, int _num) {id = _id, num = _num;}double calc() const {return a[id] *a[id] * 1.0 / num / (num + 1);}bool operator < (const node& t) const{return this->calc() < t.calc() + eps;}
};priority_queue<node> q;int main()
{scanf("%d", &t);while(t -- ) {scanf("%d%d", &n, &m);double avg = 0;for (int i = 1; i <= n; ++ i) {scanf("%d", &a[i]);avg += a[i];q.push(node(i, 1));}avg /= m;for (int i = 1; i <= m - n; ++ i) {node t = q.top();q.pop();q.push(node(t.id, t.num + 1));}double ans = 0;while(q.size()) {node t = q.top();q.pop();ans += (double)t.num * ((double)a[t.id] / t.num - avg) * ((double)a[t.id] / t.num - avg);}ans /= m;printf("Case #%d: %.9f\n", ++ kcase, ans);}return 0;
}
C、Traffic Light
阅读理解题。
“他本来可以通过修改一路遇到的全是绿灯,但是他偏要给自己找麻烦,偏要遇到一个最坏的情况,等满时间最长的红灯”
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
typedef int itn;
const int N = 500007, mod = 1e9 + 7;
const double PI = acos(-1);int n, m, t, kcase;
double maxx;int main()
{scanf("%d", &t);while(t -- ) {maxx = 0;scanf("%d", &n);double sum = 0;for(int i = 0; i <= n; ++ i) {double x;scanf("%lf", &x);sum += (double)x;}for(int i = 1; i <= n; ++ i) {double x, y;scanf("%lf%lf", &x, &y);maxx = max(maxx, y);}sum += (double)maxx;printf("Case #%d: %.8f\n", ++ kcase, sum);}return 0;
}
D、Mr. Panda and Geometric Sequence
Problem
定义happy number, 可以将数字分为三个及以上的整数,且三个整数为公比 >1 的等比数列。
询问l-r
范围内存在多少 happynumber
Solution
可以证明,分解后的等比数列第二项是小于 1e51e51e5 的。
简要证明如下:
对于每个数字 xxx ,其位数是 ⌊log10x⌋+1\lfloor log_{10}x \rfloor+1⌊log10x⌋+1,若将 yyy 与 xxx 拼接到一起,则其结果为 y×10⌊log10x⌋+1y\times 10^{\lfloor log_{10}x \rfloor+1}y×10⌊log10x⌋+1 显然 y×10⌊log10x⌋+1+x>splice(x,y)y\times 10^{\lfloor log_{10}x \rfloor+1}+x>\text{splice}(x,y)y×10⌊log10x⌋+1+x>splice(x,y) (注: splice(x,y)\text{splice}(x,y)splice(x,y) 为直接将 xyxyxy 拼接) 。
以推广,splice(a0,a1...an)>a0a1...an\text{splice}(a_0,a_1...a_n) > a_0a_1...a_nsplice(a0,a1...an)>a0a1...an 。在最坏情况下,即数列由三项组成且总长度为 151515 此时存在 a0a1a2<splice(a0,a1,a2)<=1015a_0a_1a_2< \text{splice}(a_0,a_1,a_2)<=10^{15}a0a1a2<splice(a0,a1,a2)<=1015
设等比数列公比为 qqq ,则存在 a03q3<1015{a_0}^3q^3 <10^15a03q3<1015,即:a0q<105,a1<105a_0q<10^5,a_1<10^5a0q<105,a1<105
此时我们只要在枚举首项和公比即可,设 a0=k×p×p,a1=k×p×q,a2=k×q×qa_0=k\times p\times p,a_1=k\times p\times q,a_2=k\times q\times qa0=k×p×p,a1=k×p×q,a2=k×q×q,此时公比为 qp\cfrac{q}{p}pq ( p,qp,qp,q 必须为最简分数),一直枚举下一项直到 an−1modp>0a_{n-1} \mod p > 0an−1modp>0 或总长度大于 1e15
即可。
预处理出所有happynumber, 接下来二分查询即可。
复杂度在 O(1e5×log2+T∗(log(2e6))O(1e5\times log^2+T*(log(2e6))O(1e5×log2+T∗(log(2e6))
code
#include <bits/stdc++.h>
#define reg register
#define ios ios::sync_with_stdio(false)
using namespace std;typedef long long ll;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 2e5 + 10;
const double pi = acos(-1.0);
const ll mod = 1e9 + 7;vector<ll> res;int lg(ll x) //求x的位数
{int res = 0;while(x) res++,x/=10;return res;
}ll splice(ll a, ll b) //拼接字符串
{if(lg(a) + lg(b) > 15) return 1e17; ll tmp = b, base = 1;while(tmp) base*=10,tmp/=10;a = a * base + b;return a;
}void init()
{for(ll p = 1;p <= 1e5;++p){for(ll q = p + 1;p * q <= 1e5;++q){if(__gcd(p,q) > 1) continue;for(ll k = 1;p * q * k <= 1e5;++k){ll x, y, z;x = k * p * p;y = k * p * q;z = k * q * q;ll num = splice(x,splice(y,z));res.push_back(num);ll now = z;while(1){if(now % p) break;now /= p;now *= q;num = splice(num,now);if(lg(num) > 15) break;res.push_back(num);}}}}sort(res.begin(),res.end());
}inline int slove(ll x)
{return upper_bound(res.begin(),res.end(),x) - res.begin();
}int main()
{ios;int cas = 0;init();printf("%d\n",res.size());int t;cin>>t;while(t--){ll l,r;cin>>l>>r;printf("Case #%d: %d\n",++cas, slove(r) - slove(l-1));}return 0;
}
J、Straight Master
显然这种题目要用差分来做。简单特判一下就行了。
求出来差分数组以后,如果有 +x+x+x,它的右边 555 格以内有 −x-x−x 显然可以区间消为 000,如果没有的话,可以送给它右边 555 格以内的一个整数
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main()
{ll t;ll cs = 0;scanf("%lld",&t);while(t--){ll n;scanf("%lld",&n);vector<ll> a(n + 2,0), res(n + 2);for (ll i = 1; i <= n;++i)scanf("%lld",&a[i]);for (ll i = 1; i <= n+1;++i){res[i] = a[i] - a[i - 1];}bool ok = true;for (ll i = 1; i <= n+1;++i){if(res[i] < 0){ok = false;break;}if(res[i]){for (ll j = i + 3; j <= i + 5 && j <= n+1&&res[i]>0;++j){ll tmp = res[j];if(tmp < 0){if(-tmp>=res[i]){tmp += res[i];res[i] = 0;}else{res[i] += tmp;tmp = 0;}}res[j] = tmp;}if(res[i]>0){int x = i + 3;if(x+3 <= n+1){res[x] += res[i];res[i] = 0;}else if(x<=n+1){res[n + 1] += res[i];res[i] = 0;}}}}if(ok)printf("Case #%lld: Yes\n",++cs);elseprintf("Case #%lld: No\n",++cs);}
}
H、Mr. Panda and Birthday Song
待更…
K、Downgrade
队友写的
#include <bits/stdc++.h>
using namespace std;const int maxn = 1e5 + 10;long long l[maxn];
long long sum[maxn];template<typename T>
inline T read(T &x)
{x = 0;long long f = 1;char c;while(!isdigit(c = getchar())) if(c == '-')f = -1;while(isdigit(c)){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;
}int main()
{int cas = 0;int t;read(t);while(t--){long long a, b, n;read(a), read(b), read(n);for (int i = 1; i <= a;++i){read(l[i]);sum[i] = sum[i - 1] + l[i];}long long la = a, lb = b;int pos = a;while(n--){long long tmp = a;while(sum[pos-1] >= a)pos--;a = pos;b = tmp - sum[a - 1];if(la == a && lb == b)break;la = a, lb = b;}printf("Case #%d: %lld-%lld\n",++cas, a, b);}return 0;
}
L、SOS
我花了半个小时硬推出来的,把对手逼到必败态就行了,必胜态就是组成 S__SS\_\_\ SS__ S 的局面即可,7=3+1+37=3+1+37=3+1+3 。
具体可以看这个大佬写的题解,跟我的思路差不多https://www.cnblogs.com/fan-jiaming/p/9568741.html
注意最后 161616 是因为长度至少为 161616 的话,不管先手怎么下,哪怕在中间放一个 OOO ,两边总会留有超过 777 格的空格给对手,这样后手变成了先手,而先手,777 格必胜。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
typedef int itn;
const int N = 500007, mod = 1e9 + 7;
const double PI = acos(-1);int n, m, t;
int kcase;int main()
{scanf("%d", &t);while(t -- ) {scanf("%d", &n);if((n & 1) && n >= 7) {printf("Case #%d: Panda\n", ++ kcase);}else if(((n & 1) == 0) && n >= 16) {printf("Case #%d: Sheep\n", ++ kcase);}else printf("Case #%d: Draw\n", ++ kcase);}return 0;
}
本来想打表,不会写自闭地硬推了半个小时…,赛后搜大佬的题解的打表程序学习一下:
#define FRER() freopen("i.txt","r",stdin)
#include<bits/stdc++.h>using namespace std;
typedef long long ll;
const int INF=0x3f;
const unsigned int M=1e9+9e8;
const int N=100;int a[N],n,cnt;
char mp[M];
unsigned int state()
{unsigned int ret=0;for(int i=0; i<n; ++i)ret=(ret<<1)+ret+a[i];return ret<M?ret:ret%M;
}bool check()
{for(int i=0; i+2<n; ++i)if(a[i]==1&&a[i+1]==2&&a[i+2]==1)return true;return false;
}int dfs()
{if(check())return -1;if(cnt>=n)return 0;unsigned st=state();if(mp[st]^INF)return mp[st];bool flag=false;for(int i=0; i<n; ++i){if(a[i])continue;for(int j=1; j<=2; ++j){a[i]=j;cnt++;int t=dfs();if(!~t){cnt--;a[i]=0;return mp[st]=1;}if(!t)flag=true;cnt--;a[i]=0;}}return mp[st]=(flag?0:-1);
}int main()
{//FRER();for(n=1; ; ++n){memset(mp,INF,sizeof mp);memset(a,0,sizeof a);cnt=0;printf("%d %d\n",n,dfs());}return 0;
}
M、World Cup
队友写的
#include <bits/stdc++.h>
using namespace std;
int main()
{int t;int cs = 0;scanf("%d",&t);while(t--){vector<int> num({48, 56, 60, 62, 63});vector<int> val(5);for (int i = 0; i < 5;++i)scanf("%d",&val[i]);int n;scanf("%d",&n);vector<int> a(n + 1);for (int i = 1; i <= n;++i)scanf("%d",&a[i]);sort(a.begin()+1,a.end());using ll = long long;int now = 0;ll sum = 0;for (int i = 1; i <= n;++i){while(num[now] < a[i])now++;if(a[i] <= num[now]){sum += val[now];}}sum *= 10000;printf("Case #%d: %lld\n",++cs,sum);}return 0;
}
2017-2018 ACM-ICPC Asia East Continent League Final (ECL-Final) 题解(10 / 13)相关推荐
- 【2020 ICPC Asia East Continent Final】赛前训练
这里写自定义目录标题 [2020 ICPC Asia East Continent Final]赛前训练 A - Namomo Subsequence 输入: 输出: 样例: 解析: 代码: F - ...
- The 2017 ACM-ICPC Asia East Continent League Final记录
首先感谢tyz学弟的麻麻-给我们弄到了名额- 然后就开始了ACM ECLFinal的玩耍,A*仙人掌可是立了flag要好好打的- 试机赛好像就全是GCJ kickstart的原题,然后AK了但是由于一 ...
- 2017-2018 ACM-ICPC Asia East Continent League Final (ECL-Final 2017)
地址 Rank Solved A B C D E F G H I J K L M 126/547 7/13 O O O . . . Ø O . O O . O O: 当场通过 Ø: 赛后通过 .: 尚 ...
- 2018 ACM ICPC Asia Regional - Seoul B.Cosmetic Survey
参考大佬代码 题目大意 nnn个顾客,mmm种画妆品,每一个顾客会给mmm种化妆品一个值,这个值代表这个化妆品在他心中的排名,排名越小越喜欢,如果这个值为0说明最不喜欢这一种化妆品(值为0理解为无穷大 ...
- 2020 ICPC Asia East Continent Final_K.Allin
题面: 题意: 打牌题,意思是说给你五张牌h1,h2,c1,c2,c3:除此之外本题还要考虑未给出的四张牌c4,c5,以及p1,p2. p1,p2是对面已知有的牌,h1,h2是我手上已知有的牌. c1 ...
- 2020 ICPC Asia East Continent Final D. City Brain(最短路+三分)
传送门 题意: 给出nnn 个点,mmm条边的无向带权图,初始边权都为111,一共有kkk 次操作机会,每次操作可以选择一条边使其边权+1+1+1, 通过一条边的时间为 1/1/1/边权 ,求mi ...
- 2017-2018 ACM-ICPC Asia East Continent League Final L. SOS(博弈,思维)
LINK 小范围手动模拟,发现不管怎样都可以平局,一时间不知道怎样必胜 考虑样例n=7n=7n=7的情况 先手现在中间放下一个SSS 然后不管后手怎么走,先手都在另一侧的端点放一个SSS(下面用eee ...
- 2017-2018 ACM-ICPC Asia East Continent League Final J. Straight Master(差分+思维)
LINK] 首先能每次选择长度为3,4,53,4,53,4,5的区间长度加一 相当于可以让长度大于等于333任意的区间整体加一,因为3,4,53,4,53,4,5可以凑成任意数 但这样还是不好写,考虑 ...
- 2017 ACM ICPC Asia Regional - Daejeon
2017 ACM ICPC Asia Regional - Daejeon Problem A Broadcast Stations 题目描述:给出一棵树,每一个点有一个辐射距离\(p_i\)(待确定 ...
最新文章
- php获取文件名称和扩展名
- JavaScript History对象
- 基于nginx实现minio分布式集群访问的负载均衡配置示例
- 网络共享服务Samba和NFS配置
- 63.2. 配置 Postfix
- 再次分享一个多选文件上传方案
- react(82)--方法写在effects里面
- Linux 压缩和解压命令
- 软件测试-等价类划分练习
- python自动接收邮件_Python自动发送和收取邮件的方法
- 2016-03-17 leaks 内存泄露
- 一周学C#之第4天——语句
- 详解Java中ArrayList、Vector、LinkedList三者的异同点
- Silverlight实用窍门系列:27.Silverlight二维旋转+平面渐变+动画,模拟雷达扫描图之基本框架【附带源码实例】...
- PRML中文版(马春鹏)勘误表
- velocity 将数字转为以万为单位,保留2位小数
- Eclipse — 如何恢复Eclipse中被误删除的文件
- [渝粤教育] 西南科技大学 公共关系学 在线考试复习资料
- lombok slfj 中_Lombok快速入门
- 2019牛客国庆集训派对day5 K(2017四川省赛)