HZNU ACM一日游 2019.3.17 【2,4,6-三硝基甲苯(TNT)】
Travel Diary
早上8:00到HG,听说hjc20032003在等我。
然后他竟然鸽我...最后还是勉强在8:30坐上去偏僻的HZNU的地铁。
到文新,然后带上fjl,打滴滴,一行人来到了HZNU。
早上模拟赛,先疯狂打期望概率为$\frac{1}{10}$的T1,然后26发以后过了。
后面爆推T2两圆面积交式子,然后少考虑特判情况WA了几发,后面没时间了就滚去吃饭了。
话说T3真的毒瘤,主要是英语阅读比较难(整整两页纸!!!)。
下午迟到1分钟开始模拟赛,某队伍在0:07就A了第一题?我们错过了什么。。。
先hjc上A,我想B,然后没想法,就滚去看D了,然后发现D是一个非常裸的set题,就随手码掉了。
这个时候2A,然后fjl说他想上个题,然后拿了J题,写个公式交了一发WA!,然后我检查一发,发现没开long long
于是补上,Accepted!
45分钟,作为菜鸡队的我们,成功拿下送分题ADJ。
然后我在1小时发现H题可做,就是特判1,2,3的三种情况,然后直接排序统计即可,上手20分钟1A H题。
然后hjc说他B题知道怎么做了。。就是最劣情况斐波那契数列,然后其他暴力搞,由hjc写B然后我继续翻看题面。
也没什么想法,发现K过的人比较多,但是很多次提交,一定是坑题。写K,发现K并不难想出,直接$ O(n^3+q log_2 n^3) $的复杂度就正确了。
hjc打B题比较迅速,对拍、检查,交了一发,WA!仔细再拍也没有发现什么问题,hjc认为他的结论是正确的然后开大空间,开long long,交了1发。
还是WA!此时没办法,打印代码,让我写K题,迅速的写好K题,迅速过样例,交了一发,WA!然后发现实数比较大小有精度误差,手写二分再交WA!
然后只能考虑整数二分,二分上端点的时候使用向上取整,二分下端点的时候向下取整,这样二分里面就可以做到整数比较了,然后再交还是WA!
无奈,打印代码,弃坑。
hjc说他想好G题单调队列dp,打了一发,秒过样例,交一发WA!,然后打对拍没拍出问题,后来发现没开srand,后来又发现
打错一个字母,迅速改,拍,发现暴力错了23333,交!Accepted!
此时考试结束还有1小时,我们手里有5题,然后B,K写了没过,在看B的时候我喵一眼M,发现是个博弈最后猜出sg函数,WA 1发由于筛质数筛小了。在比赛快结束的时候,我们考虑一定是B数据出锅了然后疯狂特判,最后8发,终于A了。。
还有15分钟,我看了I了,写了一发过了样例,卡时交,可惜Wa了,后来发现需要考虑反映射,其实I是个简单题。
最终带点小遗憾拿了ABDGHJM 7题,hjc 3题,ljc 4题,fjl 1题。hjc比较巨!
在参赛的266队伍中拿了rank 38-45 (按罚时是44名),获得7个气球!!!
Tips:反正我们还是太菜(主要是HGOI某队少了rym巨佬,他们只打了5题)
Problem & Solution(按照预计题目难度)
读入字符串,把末尾的句号改成感叹号。多组数据。
Sol : 考察选手会不会使用DEV C++,考察选手能否正确使用评测OJ。
复杂度$ O(T \times length) $
注意考虑多组数据还有space,那么使用getline(cin,s)读入字符串,注意该函数和scanf()一样有返回值。
# include <cstdio>
# include <iostream>
# include <cstring>
using namespace std;
string s;
int main()
{
while (getline(cin,s)) {
int len=s.length();
if (s[len-]=='.') s[len-]='!';
cout<<s<<'\n';
}
return ;
}
A.cpp
求序列中有几个不同的数字。
Sol :考察选手会不会使用STL set,本人想不出更简单的算法。
复杂度$ O(n log_2 n) $
# include<iostream>
# include<cstdio>
# include<set>
using namespace std;
set<int>s;
int main()
{
int n; scanf("%d",&n);
for (int i=;i<=n;i++){
int t; scanf("%d",&t);
s.insert(t);
}
cout<<s.size()<<'\n';
return ;
}
D.cpp
给出$n,k,t$ 表示$n$个苹果,吃$k$天,每天吃$ min\{ t , rest \} $个苹果,询问剩余几个苹果。
Sol: 比较$t \times k $和$n$的大小,若$t \times k \leq n$输出$n-t \times k$否则输出$0$
记得脑子清楚点开long long,不开long long WA一发!
复杂度 $ O(1) $
# include <cstdio>
# include <cstring>
# include <iostream>
using namespace std;
# define int long long
signed main()
{
int n,k,t; cin>>n>>k>>t;
cout<<((k*t<n)?(n-k*t):())<<'\n';
return ;
}
J.cpp
(a,b,c)记为三元组,给定一个函数$ f(a,b,c)= \frac{e^a \times e^b}{e^c} $,给出一个序列$ A $和$ m $个询问$l , r$,即求$i,j,k \in [l,r]且i\neq j\neq k$是否存在三元组($A_i,A_j,A_k$)
满足$A_i \leq A_j \leq A_k$且使得$f(A_i,B_i,C_i) > 1$成立。
对于每一个询问输出"YES"表示有,"NO"表示没有。
对于100%的数据满足 $n \leq 2\times 10^5 , A_i \leq 2^{32}-1$
Sol :一道好题,考场上hjc想出正解。
题意就是求出一序列$[l,r]$是否存在三个元素,可以组成三角形。
我们知道,组成三角形的条件是" 两个较小边之和大于最大边 ",
考虑缩放,放宽三角形组成条件为" 两个较小边之和大于等于最大边 ",
在此基础上,取最优情况是" 两个较小边之和等于最大边 ",满足斐波那契数列。
考虑斐波那契数列第多少项大于等于$2^{32}-1$,打表可知是56项。
那么对于一个区间满足$r-l+1 > 56$就可以知道无法构造一个"NO"的数据了。
我们知道对于前两个数,必然大于等于$1,1$如果每次恰好不能组成三角形,为了构造"NO"的数据,那么就必须按照斐波那契数列走下去。
如果前两个数更大或者每次不能组成三角形,那么事实上会比斐波那契数列走下去走的更少。
若考虑最差情况区间前两个数位$1,1$,每次恰好不能组成三角形,按照斐波那契数列走下去,不出56项就会和题目$A_i$的范围大。
剩下的若干个数,由鸽巢原理可知,必然可以和前面两个数都可以组成一个三角形,自然是"YES"得证。
接下来,考虑区间长度小于$56$情况,不满足上述性质,直接暴力排序,顺序扫,
若$\exists A_i + A_{i+1} > A_{i+2} , 1 \leq i \leq n-2$那么三元组($A_i , A_{i+1} , A_{i+2} $)符合条件,就是"YES"
否则就是"NO"。
Tips:做加法的时候会爆int,所以采用做减法(就不开long long气不气?)
复杂度 $ O(kn) ,k=56$
# include <cstdio>
# include <cstring>
# include <iostream>
# include <algorithm>
using namespace std;
const int N=2e5+;
int t[],a[N],n,m;
int main()
{
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++) scanf("%d",&a[i]);
while (m--) {
int l,r; scanf("%d%d",&l,&r);
if (r-l+>) { puts("YES"); continue;}
int cnt=; bool flag=false;
for (int i=l;i<=r;i++) t[++cnt]=a[i];
sort(t+,t++cnt);
for (int i=;i<=cnt-;i++)
if (t[i]>t[i+]-t[i+]) {
flag=true;break;
}
puts(flag?"YES":"NO");
}
return ;
}
B.cpp
这个题目一定要看原文(我除了扯淡两句话看的懂以外剩下就是看样例猜题面了)
26个小写字母有一组双射,求从读入的数据中能观察或推导出的关系。
Sol : 考场完全不知道是双射,然后...时间又来不及白白放弃简单的I题...
直接开map模拟正反映射,考虑双向映射合法的充要条件是1不能对多。
当正反映射都是25个成立的时候,那么第26组映射是唯一确定的。(由于只有小写字母)
复杂度 $ O(n log_2 n) $
# include <cstdio>
# include <cstring>
# include <iostream>
# include <algorithm>
# include <map>
using namespace std;
string s,t;
map<char,char>mp1,mp2;
int bo1['z'+],bo2['z'+];
int main()
{
getline(cin,s);int lens=s.length();
getline(cin,t);int lent=t.length();
int cnt1=,cnt2=;
for (int i=;i<lens;i++) {
char ss=s[i],tt=t[i];
if (mp1.count(ss)!=) {
if (mp1[ss]!=tt) {
puts("Impossible"); return ;
}
} else {
mp1[ss]=tt;
bo1[ss]=; cnt1++;
}
if (mp2.count(tt)!=) {
if (mp2[tt]!=ss) {
puts("Impossible"); return ;
}
} else {
mp2[tt]=ss;
bo2[tt]=; cnt2++;
}
}
if (cnt1==&&cnt2==) {
char op1,op2;
for (char i='a';i<='z';i++)
if (!bo1[i]) { op1=i; break;}
for (char i='a';i<='z';i++)
if (!bo2[i]) { op2=i; break;}
mp1[op1]=op2;
}
for (int i='a';i<='z';i++)
if (mp1.count(i)) printf("%c->%c\n",i,mp1[i]);
return ;
}
I.cpp
给出一序列$A$,对于每个$A_i$,求有多少个$j$,满足${A_i} ^ {A_j} > {A_j} ^ {A_i}$。
对于100%的数据 $n \leq 10^5 , A_i \leq 2^{32}-1$
Sol : 这道题考场是我A的。挺简单的,没有想象那么难。
考虑举一些例子,发现指数大的数字可能比指数小的数字都大,有没有反例呢。取1,2,3,一取一个准。
后来我尝试证明$a^b > b^a$的条件,显然$ ln $降次$ln(a^b) > ln(b^a)$,即$bln a > a ln b$由于$a,b > 0$移项,
得$\frac{ln a}{a} > \frac{ln b}{b} $考虑$ y=\frac{ln x}{x} $的单调性。
对函数$ y=\frac{ln x}{x} $求导可知$y' = \frac{\frac{1}{x} \times x - lnx\times 1}{x^2} = \frac{1-lnx}{x^2}$
令$y'=0$得$x = e$ 那么 就以$e=2.7$作为基准,有3个特例$1,2,3$就打表特判贡献即可。
复杂度 $ O(n log_2 n) $
# include <cstdio>
# include <cstring>
# include <iostream>
# include <algorithm>
# include <map>
# define int long long
using namespace std;
const int N=1e5+;
int a[N],t[N],cnt,n,ans[N];
int find(int x)
{
int l=,r=cnt,ans=-;
while (l<=r) {
int mid=(l+r)/;
if (t[mid]>=x) r=mid-,ans=mid;
else l=mid+;
}
if (ans==-) return ;
return cnt-ans+;
}
signed main()
{
scanf("%lld",&n);
int cnt1,cnt2,cnt3;cnt1=cnt2=cnt3=;
for (int i=;i<=n;i++) {
scanf("%lld",&a[i]);
if (a[i]==) cnt1++;
else if (a[i]==) cnt2++;
else if (a[i]==) cnt3++;
if (a[i]>) t[++cnt]=a[i];
}
sort(t+,t++cnt);
for (int i=;i<=n;i++) {
if (a[i]==) printf("0 ");
else if (a[i]==) printf("%lld ",cnt1+find());
else if (a[i]==) printf("%lld ",cnt1+cnt2+find());
else printf("%lld ",cnt1+find(a[i]+));
}
puts("");
return ;
}
H.cpp
给出n个整数坐标点,给出$m$个询问,求这些点中可以互相构成三角形或者点的面积在$ [l,r]$的有多少个。
对于100%的数据$n \leq 250 , m\leq 10^5$
Sol : 本题是我打的,使用海伦公式疯狂WA。由于求距离,三边求面积开2次根号,精度误差太大。
尽管塞入容器二分的时候考虑上取整枚举上界,下取整枚举上界避免小数比较大小,但是还是由于比较强的数据WA了。
没有想到皮克定律(个点三角形面积最小分度值为0.5,证明的话就弄个坐标矩形框三角形即可)。
考虑怎么求格点三角形面积,使用向量外积即叉乘。可以推倒结论
对于$ A(x_1,y_1), B(x_2,y_2), C(x_3,y_3)$围成面积$S = | \frac{1}{2} \times {(x_1 y_2 - x_2 y_1)+(x_2 y_3 - x_3 y_2)+(x_3 y_1-x_1 y_3)} |$
然后全部乘以2,就可以全整数运算了。
复杂度 $ O(n^3 + m log_2 n^3) $
# include <cstdio>
# include <iostream>
# include <cstring>
# include <algorithm>
# define int long long
using namespace std;
const int N=+;
struct rec{
int x,y;
}a[N];
int t[N*N*N/],n,m,cnt;
int Fun(int x)
{
if (x<) return -x;
else return x;
}
signed main()
{
scanf("%lld%lld",&n,&m);
for (int i=;i<=n;i++)
scanf("%lld%lld",&a[i].x,&a[i].y);
for (int i=;i<=n;i++)
for (int j=i+;j<=n;j++)
for (int k=j+;k<=n;k++)
t[++cnt]=Fun((a[i].x*a[j].y-a[j].x*a[i].y)+(a[j].x*a[k].y-a[k].x*a[j].y)+(a[k].x*a[i].y-a[i].x*a[k].y));
sort(t+,t++cnt);
while (m--) {
int l,r; scanf("%lld%lld",&l,&r);
l<<=; r<<=;
int L=lower_bound(t+,t++cnt,l)-t;
int R=upper_bound(t+,t++cnt,r)-t-;
if (R<L) puts("");
else printf("%lld\n",R-L+);
}
return ;
}
K.cpp
M. Little Sub and Johann
石子游戏,要不取一堆,要不取x个且gcd(x,该堆石子个数)=1,问谁会赢。
考虑打表求sg函数,若x是质数那么$ sg(x)=\max\limits_{i=0}^{x-1} \{ sg(i) \} +1 $
若x是合数,那么$sg(x)=sg(y),y为x最小质因数$
所以一边筛法就可以求出sg函数了。下面会给出证明:
#include <cstdio>
#include <iostream>
using namespace std;
const int N=;
int t,n,sg[N+],k,ans,x;
void find_prime()
{
sg[]=k=;
for (int i=;i<=N;i++)
{
if (sg[i]) continue;
sg[i]=++k;
for (int j=i;j<=N;j+=i)
if (!sg[j]) sg[j]=k;
}
return;
}
int main()
{
scanf("%d",&t);
find_prime();
while (t--)
{
scanf("%d",&n); ans=;
for (int i=;i<=n;i++) scanf("%d",&x),ans^=sg[x];
if (ans) printf("Subconscious is our king!\n");
else printf("Long live with King Johann!\n");
}
return ;
}
M.cpp
对于n个物品有价格w[i],快乐值v[i]。
每天能往存钱罐加任意实数的钱,每天放的钱数需要小于等于前一天放的钱数。
如果某 一天的钱数恰好等于那天的特价商品,则可以买,获得那个物品的快乐值,
求最后的最大快乐值。
对于100%的数据$ n \leq 2000 $
Sol : 本题考场是hjc 2A的,考场想了个单调队列+二分维护一个转移。
f[i][j]表示从i天开始(第i天rest 0块钱),到第j天买(买第j个商品),最大happiness值
显然$\max\limits_{j=1}^{n} \{ f[1][j] \}$就是答案。
对于朴素转移,考虑i->j->k合法,那么有$ f[i][j]=\max\{f[j+1][k]\}+v[i] $
考虑i->j->k合法的条件,那么就是一个贪心,即为了买第j个物品,那么在[i+1,j]每天加入$\frac{w[j]}{j-i}$块钱。
同理,为了买第k个物品那么在[j+1,k]每天加入$\frac{w[k]}{k-j}$块钱。
所以转移的条件就是$\frac{w[j]}{j-i} \geq \frac{w[k]}{k-j}$
考虑每个确定的i,维护$ f[i][k] $一个单调栈,只在队尾插入,队尾弹出,且满足决策值$ f[i][k] $单调递减,k和i之间买的物品每天平摊价格$\frac{w[k]}{k-i}$单调递减的单调栈。
对于每次转移,只需要在单调栈里面二分出一个符合条件的每天平摊价格,从对应的决策值转移即可。
时间复杂度$ O(n^2 log_2 n)$
事实上,本题还有$O(n^2)$的dp做法,是使用后缀max维护的。
令f[i][j]表示最后两个被买的物品为i号j号($i<j$),也可以为空但要特殊判断。
考虑p->j->i转移合法。根据上面的分析,可以知道$p\geq \left \lceil j-\frac{(i-j) \times w[j] }{w[i]} \right \rceil$
转移是$f[i][j]=\max\limits_{p=\left \lceil j-\frac{(i-j) \times w[j] }{w[i]} \right \rceil}^{i-1} \{ f[p][j] \}+v[i] $
考虑维护后缀和g[i][j]维护对于一个确定的j,f[i][j]的后缀最大值,即$ g[i][j]=\max\limits_{k=i}^{j-1} \{f[k][j]\} $
那么上面的转移就可以转化为$f[j][i]=g[p][j]+v[i] , p= \left \lceil j-\frac{(i-j) \times w[j] }{w[i]} \right \rceil $
注意一些细节,如果p对于全局合法(即$ p\leq 0 $),那么令p=1,但会造成一些非法的转移,所以需要设初始值全局为-INF,排除一些奇怪的不合法情况。
特判只有2个的初始情况,即仅取(j,i)时的初始值,即当$f[j][i]=v[j]+v[i] , (\frac{w[j]}{j} \geq \frac{w[i]}{i-j})$
调了好久的代码....
复杂度$ O(n^2) $
# include <cstdio>
# include <cstring>
# include <iostream>
# include <cmath>
# define int long long
using namespace std;
const int N=2e3+;
int w[N],v[N],n,ans;
int f[N][N],g[N][N];
signed main()
{
scanf("%lld",&n);
for (int i=;i<=n;i++) scanf("%lld",&w[i]);
for (int i=;i<=n;i++) scanf("%lld",&v[i]);
memset(g,~0x3f,sizeof(g));
memset(f,~0x3f,sizeof(f));
for (int i=;i<=n;i++)
for (int j=i-;j>=;j--)
{
int p=max((int)ceil((double)j-(double)(i-j)*w[j]/(double)w[i]),1ll);
if ((i-j)*w[j]>=w[i]*j) f[j][i]=max(f[j][i],v[i]+v[j]);
f[j][i]=max(f[j][i],g[p][j]+v[i]);
g[j][i]=max(g[j+][i],f[j][i]);
ans=max(ans,f[j][i]);
}
cout<<ans<<'\n';
return ;
}
G.cpp
HZNU ACM一日游 2019.3.17 【2,4,6-三硝基甲苯(TNT)】的更多相关文章
- 2019/01/17 基于windows使用fabric将gitlab的文件远程同步到服务器(git)
觉得django项目把本地更新push到gitlab,再执行fabric脚本从gitlab更新服务器项目挺方便的,当然从本地直接到服务器就比较灵活. 2019/01/17 基于windows使用fab ...
- Sqlite && EF Code FIRST 终极解决方案 2019.5.17
Sqlite && EF Code FIRST 终极解决方案 2019.5.17 包括根据模型自动生成数据库,初始化数据,模型改变时的自动数据迁移等 2019.12.25 更新 支持E ...
- [2019/03/17#杭师大ACM]赛后总结(被吊锤记)
前言 和扬子曰大佬和慕容宝宝大佬一组,我压力巨大,而且掌机,累死我了,敲了一个下午的代码,他们两个人因为比我巨就欺负我QwQ. 依旧被二中学军爆锤,我真的好菜,慕容宝宝或者是扬子曰大佬来掌机一定成绩比 ...
- 【2019.10.17】十天Web前端程序员体验(软件工程实践第五次作业)
结对信息.具体分工 Github地址:https://github.com/MokouTyan/131700101-031702425 学号 昵称 主要负责内容 博客地址 131700101 莫多 代 ...
- 2019/4/17 wen 注解、垃圾回收、多线程
- 2019.1.17 homework
1.求两个整型数较大值 #include<stdio.h>int compare_big(int var1,int var2);int main(void){ int big,x,y ...
- 2019/4/17 Linux学习
一.Linux的文件系统 其中/prov./srv./sys 文件为文件系统,技术不过硬不要去修改:二.关于Xshell.Xft1.服务器的端口可有65535个可设置,开的越多安全性越差:2.远程登录 ...
- Python脱产8期 Day05 2019/4/17
数据类型的使用 一 数字类型 1.整型:int 2.浮点型:float 3.重点:数字类型直接相互转化 二字符串类型 一 1.定义:在单引号/双引号/三引号中包含一系列字符. 2.注意:可以通过引号的 ...
- 2019.02.17 spoj Query on a tree VII(链分治)
传送门 跟QTREE6QTREE6QTREE6神似,改成了求连通块里的最大值. 于是我们对每条链开一个heapheapheap维护一下即可. MDMDMD终于1A1A1A链分治了. 代码: #incl ...
随机推荐
- html总结:固定表格中单元格宽度
当然要提前设置好table的width值,然后再写这个,使得每列宽度都相等. <style> table { table-layout: fixed; } </style>
- 快速失败/报错机制 - fail-fast
一.快速报错机制(fail-fast) 这是<Java编程思想>中关于快速报错机制的描述 Java容器有一种保护机制,能够防止多个进程同时修改同一个容器的内容.如果在你迭代遍历容器的过程中 ...
- 多线程系列之三:Immutable 模式
一,什么是Immutable模式?immutable就是不变的,不发生改变的.Immutable模式中存在着确保实例状态不发生变化改变的类.这些实例不需要互斥处理.String就是一个Immutabl ...
- Hive基础
一.常用语句 二.嵌套语句 以上两句的查询结果相同. 三.关键字查询
- 敏捷与CMM的恩怨
模式不同,一种是灵活,一种是严肃.
- 遍历List过程中删除操作报java.util.ConcurrentModificationException错误
1:遍历List 同时 remove 元素,出现java.util.ConcurrentModificationException错误 @Test public void test3(){ List& ...
- Laravel技巧:使用load、with预加载 区别
1.使用load $posts = Post::all(); $posts->load('user'); 2.使用with $posts = Post::with('user')->all ...
- C# Note34: 异常机制相关小点
1.使用throw和throw ex抛出异常的区别 通常,我们使用try/catch/finally语句块来捕获异常,那么在抛出异常的时候,使用throw和throw ex有什么区别呢? 假如,按顺序 ...
- 用户认证--------------auth模块
一.auth模块 from django.contrib import auth 1 .authenticate() :验证用户输入的用户名和密码是否相同 提供了用户认证,即验证用户名以及密码是否 ...
- Android——SMS接收发短信与运行权限
好久没写了,最近学习Android的相关知识,包括UI组件与布局.Activity生命周期等,而这次要讲的是,Broadcast Receiver的相关知识,主要是接收发短信,SmsManager.S ...