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⌊log10​x⌋+1,若将 yyy 与 xxx 拼接到一起,则其结果为 y×10⌊log10x⌋+1y\times 10^{\lfloor log_{10}x \rfloor+1}y×10⌊log10​x⌋+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⌊log10​x⌋+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​)>a0​a1​...an​ 。在最坏情况下,即数列由三项组成且总长度为 151515 此时存在 a0a1a2<splice(a0,a1,a2)<=1015a_0a_1a_2< \text{splice}(a_0,a_1,a_2)<=10^{15}a0​a1​a2​<splice(a0​,a1​,a2​)<=1015

设等比数列公比为 qqq ,则存在 a03q3<1015{a_0}^3q^3 <10^15a0​3q3<1015,即:a0q<105,a1<105a_0q<10^5,a_1<10^5a0​q<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−1​modp>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)相关推荐

  1. 【2020 ICPC Asia East Continent Final】赛前训练

    这里写自定义目录标题 [2020 ICPC Asia East Continent Final]赛前训练 A - Namomo Subsequence 输入: 输出: 样例: 解析: 代码: F - ...

  2. The 2017 ACM-ICPC Asia East Continent League Final记录

    首先感谢tyz学弟的麻麻-给我们弄到了名额- 然后就开始了ACM ECLFinal的玩耍,A*仙人掌可是立了flag要好好打的- 试机赛好像就全是GCJ kickstart的原题,然后AK了但是由于一 ...

  3. 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: 当场通过 Ø: 赛后通过 .: 尚 ...

  4. 2018 ACM ICPC Asia Regional - Seoul B.Cosmetic Survey

    参考大佬代码 题目大意 nnn个顾客,mmm种画妆品,每一个顾客会给mmm种化妆品一个值,这个值代表这个化妆品在他心中的排名,排名越小越喜欢,如果这个值为0说明最不喜欢这一种化妆品(值为0理解为无穷大 ...

  5. 2020 ICPC Asia East Continent Final_K.Allin

    题面: 题意: 打牌题,意思是说给你五张牌h1,h2,c1,c2,c3:除此之外本题还要考虑未给出的四张牌c4,c5,以及p1,p2. p1,p2是对面已知有的牌,h1,h2是我手上已知有的牌. c1 ...

  6. 2020 ICPC Asia East Continent Final D. City Brain(最短路+三分)

    传送门 题意: 给出nnn​​ 个点,mmm条边的无向带权图,初始边权都为111,一共有kkk 次操作机会,每次操作可以选择一条边使其边权+1+1+1, 通过一条边的时间为 1/1/1/边权 ,求mi ...

  7. 2017-2018 ACM-ICPC Asia East Continent League Final L. SOS(博弈,思维)

    LINK 小范围手动模拟,发现不管怎样都可以平局,一时间不知道怎样必胜 考虑样例n=7n=7n=7的情况 先手现在中间放下一个SSS 然后不管后手怎么走,先手都在另一侧的端点放一个SSS(下面用eee ...

  8. 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可以凑成任意数 但这样还是不好写,考虑 ...

  9. 2017 ACM ICPC Asia Regional - Daejeon

    2017 ACM ICPC Asia Regional - Daejeon Problem A Broadcast Stations 题目描述:给出一棵树,每一个点有一个辐射距离\(p_i\)(待确定 ...

最新文章

  1. php获取文件名称和扩展名
  2. JavaScript History对象
  3. 基于nginx实现minio分布式集群访问的负载均衡配置示例
  4. 网络共享服务Samba和NFS配置
  5. 63.2. 配置 Postfix
  6. 再次分享一个多选文件上传方案
  7. react(82)--方法写在effects里面
  8. Linux 压缩和解压命令
  9. 软件测试-等价类划分练习
  10. python自动接收邮件_Python自动发送和收取邮件的方法
  11. 2016-03-17 leaks 内存泄露
  12. 一周学C#之第4天——语句
  13. 详解Java中ArrayList、Vector、LinkedList三者的异同点
  14. Silverlight实用窍门系列:27.Silverlight二维旋转+平面渐变+动画,模拟雷达扫描图之基本框架【附带源码实例】...
  15. PRML中文版(马春鹏)勘误表
  16. velocity 将数字转为以万为单位,保留2位小数
  17. Eclipse — 如何恢复Eclipse中被误删除的文件
  18. [渝粤教育] 西南科技大学 公共关系学 在线考试复习资料
  19. lombok slfj 中_Lombok快速入门
  20. 2019牛客国庆集训派对day5 K(2017四川省赛)

热门文章

  1. 综述:解决目标检测中的样本不均衡问题
  2. 绝对不容错过:最完整的检测模型评估指标mAP计算指南(附代码)在这里!
  3. 如何解决uiaotomator定位工具报错
  4. redhat7配置本地yum、163 yum、epel 源
  5. 王立飞:专注己之长 跨界求发展
  6. ecshop入门第一步,替换ecshop模板的显示图片
  7. 使用 Docker 搭建 Laravel 本地环境
  8. vi profile
  9. VirtualBox虚拟机中启用usb3.0却无法显示u盘的解决方法
  10. 转:一个android开发者独立开发社交app全过程