终于到了饭吉圆杯的开赛,这是EZ我参与的历史上第一场ACM赛制的题目然而没有罚时

不过题目很好,举办地也很成功,为法老点赞!!!

这次和翰爷,吴骏达 dalao,陈乐扬dalao组的队,因为我们有二个初二的,所以并起来算一个 。

然后我和另外一个初二的连键盘都没摸,靠着翰爷的大杀四方成功A了5题并因为罚时惜败得到Rank2。%%%Orz 翰爷%%%

好了下面开始讲题。饭吉圆链接

与一般的ACM相似,这次考试的题目也分为三档

  • Easy:NOIp普及组+难度(法老认为);NOIp提高组T1,T2难度(我认为)
  • Medium:比较套路略加一点思维的NOIp提高组题 (法老认为);NOIpT3+至弱省省选题(我认为)
  • Hard: 省选常见算法题,难度略低于省选(法老认为);ZJOI/HNOI省选题+NOI-神题(我认为)

好了我是真的菜,并且针对我无比菜的水平,我也只改了Easy+Medium。

Easy(难度递增)

I. 「QZEZ第一届“饭吉圆”杯程序设计竞赛」画展

整场比赛最水的题目了,模拟题不解释。

由于\(n\le 111\),因此连Hash都不用上。我们直接把图变成字符串然后开Map存一下即可

CODE

#include<iostream>
#include<cstdio>
#include<map>
#include<string>
using namespace std;
const int N=120;
map <string,bool> t;
int n,m,a,b,ans;
char g[N][N];
bool vis[N][N];
string s;
inline void find(void)
{
for (register int i=2;i<=n;++i)
if (g[i][2]=='#') { a=i-2; break; }
for (register int i=2;i<=m;++i)
if (g[2][i]=='#') { b=i-2; break; }
}
inline void solve(int x1,int y1,int x2,int y2)
{
register int i,j;
for (s="",i=x1;i<=x2;++i)
for (j=y1;j<=y2;++j)
s+=g[i][j],vis[i][j]=1;
if (t[s]) return;
for (s="",i=x2;i>=x1;--i)
for (j=y2;j>=y1;--j)
s+=g[i][j];
if (t[s]) return;
if (a==b)
{
for (s="",j=y2;j>=y1;--j)
for (i=x1;i<=x2;++i)
s+=g[i][j];
if (t[s]) return;
for (s="",j=y1;j<=y2;++j)
for (i=x2;i>=x1;--i)
s+=g[i][j];
if (t[s]) return;
}
t[s]=1; ++ans;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register int i,j; ios::sync_with_stdio(false); cin>>n>>m;
for (i=1;i<=n;++i)
for (j=1;j<=m;++j)
cin>>g[i][j]; find();
for (i=1;i<=n;++i)
for (j=1;j<=m;++j)
if (g[i][j]!='#'&&!vis[i][j]) solve(i,j,i+a-1,j+b-1);
return printf("%d",ans),0;
}

F. 「QZEZ第一届“饭吉圆”杯程序设计竞赛」数学作业

这道题有两种方法。

第一种当然是暴力证明了,由于我不会,因此给出法老的手写证明

第二种就比较策略了。题目中提到了:

\(f(s)\)的函数图像似乎是一个极其诡异的曲线

然后我们根据相似三角形感性理解一下其实面积变大的话其形状不会改变,只有边长会按比例增加。

因此我们可以结合样例得到:

\(f(s)=A \sqrt S=1.63299\sqrt S\)

然后写上去一交发现WA了!Why?精度!

我们来猥琐一波:

\((1.63299)^2=2.666...=\frac{8}{3}\)

所以\(A=\frac{2\sqrt S}{3}\)

然后就水过了。

CODE

#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
int n; scanf("%d",&n);
printf("%.5lf",(double)sqrt(n*8.0/3.0));
return 0;
}

B. 「QZEZ第一届“饭吉圆”杯程序设计竞赛」最小完美生成树

也是比较简单的题目,要正确理解题意

首先我们先对原图跑一遍MST,如果求出来的MST已经包含多种颜色,那么直接输出答案即可。

如果只有一种颜色,我们就挑一条不同颜色的边,然后肯定会有一条边被替换下来。

我们找到这条边的最大值即可。

这种方法可以和求LCA一起搞,主要就是倍增。

令\(f_{i,j}\)表示第\(i\)条边向上\(2^j\)次步的路径上的最大值,然后和LCA一起做即可(因为刚好也查询到LCA)

具体维护看CODE

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100005,P=20;
struct edge
{
int to,next,v;
}e[N<<1];
struct data
{
int l,r,w,col;
bool use;
}a[N];
int head[N],n,m,pa[N][P],f[N][P],father[N],dep[N],cnt,c,rt=1;
long long tot;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch=tc();
while (ch<'0'||ch>'9') ch=tc();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
inline bool comp(data a,data b)
{
return a.w<b.w;
}
inline void add(int x,int y,int z)
{
e[++cnt].to=y; e[cnt].v=z; e[cnt].next=head[x]; head[x]=cnt;
}
inline int max(int a,int b)
{
return a>b?a:b;
}
inline int min(int a,int b)
{
return a<b?a:b;
}
inline int getfather(int k)
{
return father[k]==k?k:father[k]=getfather(father[k]);
}
inline void DFS(int now,int fa)
{
for (register int i=head[now];i!=-1;i=e[i].next)
if (e[i].to!=fa) f[e[i].to][0]=e[i].v,pa[e[i].to][0]=now,dep[e[i].to]=dep[now]+1,DFS(e[i].to,now);
}
inline void init(void)
{
for (register int j=0;j<P-1;++j)
for (register int i=1;i<=n;++i)
if (pa[i][j]) pa[i][j+1]=pa[pa[i][j]][j],f[i][j+1]=max(f[i][j],f[pa[i][j]][j]);
}
inline void swap(int &a,int &b)
{
int t=a; a=b; b=t;
}
inline int getmax(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y); register int i; int res=0;
for (i=P-1;i>=0;--i)
if (pa[x][i]&&dep[pa[x][i]]>=dep[y]) res=max(res,f[x][i]),x=pa[x][i];
if (x==y) return res;
for (i=P-1;i>=0;--i)
if (pa[x][i]&&pa[y][i]&&pa[x][i]!=pa[y][i])
{
res=max(res,max(f[x][i],f[y][i]));
x=pa[x][i]; y=pa[y][i];
}
return max(res,max(f[x][0],f[y][0]));
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register int i; read(n); read(m);
memset(e,-1,sizeof(e));
memset(head,-1,sizeof(head));
for (i=1;i<=m;++i)
read(a[i].l),read(a[i].r),read(a[i].w),read(a[i].col);
sort(a+1,a+m+1,comp);
for (i=1;i<=n;++i)
father[i]=i;
for (i=1;i<=m;++i)
{
int fx=getfather(a[i].l),fy=getfather(a[i].r);
if (fx!=fy)
{
father[fx]=fy; tot+=a[i].w; a[i].use=1;
add(a[i].l,a[i].r,a[i].w); add(a[i].r,a[i].l,a[i].w);
}
}
for (i=1;i<=m;++i)
if (a[i].use)
{
if (!c) { c=a[i].col; continue; }
if (c!=a[i].col) return printf("%lld",tot),0;
}
DFS(rt,-1); init(); long long ans=1e18;
for (i=1;i<=m;++i)
if (!a[i].use&&a[i].col!=c) ans=min(ans,tot-getmax(a[i].l,a[i].r)+a[i].w);
return printf("%lld",ans),0;
}

Medium(难度递增)

C. 「QZEZ第一届“饭吉圆”杯程序设计竞赛」路径计数

比较套路的数位DP

我们考虑对题意进行转换,考虑把走过的点写下来,那么一个点的二进制是另一个点的二进制的子集

所以每一个路径上的数肯定是一段1,然后一段0。

就相当于要确定二进制每一位的出现次数,然后出现的二进制位值之和要小于等于\(k\),总和等于\(n\)

仔细想一想,这就是个多重背包了(怎么好像就我一个人写多重背包)

CODE

#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
const int N=1e5+5,mod=1e9+9;
int n,k,f[N],x;
inline void inc(int &x,int y)
{
if ((x+=y)>=mod) x-=mod;
}
inline void dec(int &x,int y)
{
if ((x-=y)<0) x+=mod;
}
int main()
{
register int i,j; scanf("%d%d",&k,&n); f[0]=1;
for (i=0;(x=1<<i)<=n;++i)
{
for (j=0;j<=n;++j)
if (j>=x) inc(f[j],f[j-x]);
for (j=n;j>=0;--j)
if (j>=(long long)x*(k+1)) dec(f[j],f[j-(long long)x*(k+1)]);
}
return printf("%d",f[n]),0;
}

K. 「QZEZ第一届“饭吉圆”杯程序设计竞赛」朋友圈

这是典型的技巧题,首先我们想一下这个问题的两种解决方法:

  1. 暴力扫描每一条边,判断两端是否在点集内。复杂度为\(O(qm)\)
  2. 枚举点集中的两个点,然后判断是否存在边 。复杂度为\(O(q\cdot s\ log\ m)\)

然后这两种算法的效率取决于每组数据的点数。我们设一个阈值\(S\):

当点数大于\(S\)时进行算法1,否则进行算法2。

然后我们可以得出取\(S=\frac{q}{log\ m}\)时复杂度达到理论最小值\(O(q\cdot\sqrt{m\ log\ m})\)

CODE

#include<cstdio>
#include<cctype>
#include<cmath>
#include<map>
#include<set>
using namespace std;
const int N=200005;
struct edge
{
int x,y;
}e[N];
map <int,bool> vis[N];
int n,m,q,blk,t,ans,num[N];
bool s[N];
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(int x)
{
if (x>9) write(x/10);
putchar(x%10+'0');
}
inline int solve1(void)
{
register int i,ans=0;
for (i=1;i<=m;++i)
if (s[e[i].x]&&s[e[i].y]) ++ans;
return ans;
}
inline int solve2(void)
{
register int i,j,ans=0;
for (i=1;i<t;++i)
for (j=i+1;j<=t;++j)
if (vis[num[i]][num[j]]) ++ans;
return ans;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register int i; read(n); read(m);
for (i=1;i<=m;++i)
read(e[i].x),read(e[i].y),vis[e[i].x][e[i].y]=vis[e[i].y][e[i].x]=1;
read(q); blk=q/(int)log2(m);
while (q--)
{
for (read(t),i=1;i<=t;++i)
read(num[i]),s[num[i]]=1;
write(t>blk?solve1():solve2()); putchar('\n');
for (i=1;i<=t;++i)
s[num[i]]=0;
}
return 0;
}

H. 「QZEZ第一届“饭吉圆”杯程序设计竞赛」字符串匹配2

这道题也是有点骚的,就着法老的std写的,第一次知道双Hash的正确写法

首先读题,我们考虑枚举所有的周期,然后对于每一段我们可以结合特殊最小表示法+双Hash来\(O(1)\)求

然后这里我们要知道一个调和级数公式(其实我是知道的,也和另外一个初二口头AC了这道题,不过最后时间不够了,而且我们也不敢上):

\(n+\frac{n}{2}+\frac{n}{3}+\frac{n}{4}+\cdots+\frac{n}{n-1}+1=n\ In\ n\)

然后把每种字符出现的位置用01二进制串表示,然后hash,判断是否能两两对应就可以了 。

CODE

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define fir first
#define sec second
using namespace std;
typedef pair<int,int> Hash;
const int N=1e5+5;
const Hash seed={233,2333},mod={1e9+7,1e9+9};
vector <Hash> a,b;
char s[N];
int len;
Hash pre[5][N],pw[N];
Hash operator %(Hash a,Hash b) { return Hash((a.fir+b.fir)%b.fir,(a.sec+b.sec)%b.sec); }
Hash operator +(Hash a,Hash b) { return Hash(a.fir+b.fir,a.sec+b.sec)%mod; }
Hash operator -(Hash a,Hash b) { return Hash(a.fir-b.fir,a.sec-b.sec)%mod; }
Hash operator *(Hash a,Hash b) { return Hash(1LL*a.fir*b.fir%mod.fir,1LL*a.sec*b.sec%mod.sec); }
inline void write(int x)
{
if (x>9) write(x/10);
putchar(x%10+'0');
}
inline int min(int a,int b)
{
return a<b?a:b;
}
inline Hash get_sub(int k,int l,int r)
{
return pre[k][r]-(pre[k][l-1]*pw[r-l+1]);
}
int main()
{
register int i,j,k; scanf("%s",s+1); len=strlen(s+1);
for (pw[0]={1,1},i=1;i<=len;++i)
pw[i]=pw[i-1]*seed;
for(i=1;i<=len;++i)
{
for(j=0;j<5;++j)
pre[j][i]=pre[j][i-1]*seed;
pre[s[i]-'a'][i]=pre[s[i]-'a'][i]+Hash(1,1);
}
for (i=1;i<=len;++i)
{
bool flag=1;
for (j=i+1;j<=len;j+=i)
{
a.clear(); b.clear();
for (k=0;k<5;++k)
a.push_back(get_sub(k,1,min(i,len-j+1))),b.push_back(get_sub(k,j,min(i+j-1,len)));
sort(a.begin(),a.end()); sort(b.begin(),b.end());
if (a!=b) { flag=0; break; }
}
if (flag) write(i),putchar(' ');
}
return 0;
}

E. 「QZEZ第一届“饭吉圆”杯程序设计竞赛」暑假作业

首先先发现对\(t\)从小到大排序后可以得到最优解(这个很好证明而且也很显然,实在不行结合样例理解一下即可)。

考虑排序后如何算出初始的最优解,我们可以分析后得出答案等价于

\(\sum_{i=1}^n l_i-t_i\cdot(n-i+1)\)

然后我们考虑修改,其实就是取走一个数在放上一个数的过程,我们发现只要得出这个点(老的)对答案的贡献和新的点对答案的贡献。

很显然,一个点被删除/加入对于它的排名有影响,对排在它后面的数的答案也有影响。

因此我们分别考虑这两个影响,排名可以用类似于求逆序对的方法用树状数组求知。

然后考虑对于排在它后面的数统统前移一位,其实也是一个求和(\(\sum t_i\))的过程,因此我们再开一维树状数组来直接统计即可。

具体实现看CODE

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL N=2e5+5;
LL n,m,l[N],t[N],r[N],x,nl,nt,ans,tree[2][N>>1];
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(LL x)
{
if (x<0) putchar('-'),x=-x;
if (x>9) write(x/10); putchar(x%10+'0');
}
inline void add(LL x,LL y,LL z)
{
for (;x<=1e5;tree[z][x]+=y,x+=x&-x);
}
inline LL get(LL x,LL y)
{
LL tot=0; for (;x;tot+=tree[y][x],x-=x&-x); return tot;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register LL i; read(n); read(m);
for (i=1;i<=n;++i)
read(l[i]),read(t[i]),r[i]=t[i],ans+=l[i];
sort(r+1,r+n+1);
for (i=1;i<=n;++i)
ans-=r[i]*(n-i+1),add(r[i],1,0),add(r[i],r[i],1);
write(ans); putchar('\n');
while (m--)
{
read(x); read(nl); read(nt);
ans-=l[x]; l[x]=nl; ans+=l[x];
add(t[x],-1,0); add(t[x],-t[x],1);
ans+=t[x]*(n-get(t[x],0))+get(t[x],1);
t[x]=nt; ans-=t[x]*(n-get(t[x],0))+get(t[x],1);
add(t[x],1,0); add(t[x],t[x],1);
write(ans); putchar('\n');
}
return 0;
}

QZEZ第一届“饭吉圆”杯程序设计竞赛的更多相关文章

  1. 华南理工大学“三七互娱杯”程序设计竞赛(重现赛)( HRY and array 高精度除法模板)

    题目链接:https://ac.nowcoder.com/acm/contest/874/D 题目大意:给你两个数列a和b然后对a可以进行排列,对b可以任意排列,问你sigma(a(i)*b(i))的 ...

  2. 华南理工大学“三七互娱杯”程序设计竞赛 HRY and codefire(概率期望DP)

    https://ac.nowcoder.com/acm/contest/874/A 题目:有两个账号 , 一开始都为0级 , 求任意一个账号升级到N的期望 要求:如果当前账号嬴了 , 就继续沿用当前的 ...

  3. 长安大学第四届ACM-ICPC“迎新杯”程序设计竞赛-重现赛 G - 彩虹岛套娃

    题目描述 俄罗斯套娃是俄罗斯特产的木制玩具,一般由多个一样图案的空心木娃娃一个套一个组成,最多可达十多个,通常为圆柱形,底部平坦可以直立.颜色有红色,蓝色,绿色,紫色等.最普通的图案是一个穿着俄罗斯民 ...

  4. 长安大学第四届ACM-ICPC“迎新杯”程序设计竞赛-重现赛 H - 圣诞节糖果

    题目描述 圣诞节临近,彩虹岛的黑心商人

  5. 长安大学第四届ACM-ICPC“迎新杯”程序设计竞赛-重现赛 F - 打铁的箱子

    题目描述 作为彩虹岛上最擅长打铁的人,

  6. 长安大学第四届ACM-ICPC“迎新杯”程序设计竞赛-重现赛 D - 新卡片游戏

    题目描述

  7. 长安大学第四届“迎新杯”程序设计竞赛 F 打铁的箱子【数学/进制思维/折半枚举】

    题目描述 作为彩虹岛上最擅长打铁的人,

  8. 长安大学第四届“迎新杯”程序设计竞赛 H 圣诞节糖果【二分】

    时间限制:C/C++ 1秒,其他语言2秒空间限制:C/C++ 131072K,其他语言262144K64bit IO Format: %lld 题目描述 圣诞节临近,彩虹岛的黑心商人

  9. 华南理工大学“三七互娱杯”程序设计竞赛 G: HRY and tree

    题意:给出一棵树,定义两点间代价为两点路径上最长的边权,问任两点间的代价和. 解法:这道题的解法十分巧妙:直接用Kruskal对这棵树求最小生成树,然后对于即将加入到MST的这条边(u,v,w),这条 ...

随机推荐

  1. Android6.0源码下载编译刷入真机

    编译环境是Ubuntu12.04.手机nexus 5,编译安卓6.0.1源码并烧录到真机. 源码用的是科大的镜像:http://mirrors.ustc.edu.cn/aosp-monthly/,下载 ...

  2. Android基础之6.0系统以上的权限分配

    public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle saved ...

  3. spring ApplicationContext中Bean的生命周期

    AbstractApplicationContext Spring的AbstractApplicationContext是ApplicationContext的抽象实现类,该抽象类的refresh方法 ...

  4. ES6 入门

    1.简介 ECMAScript 6.0 是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了.它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序, ...

  5. js,ajax,layer笔记(弹出层,在弹出一个弹框)

    整体认识: 因为作用域的问题,js 在页面初次加载时已近加载好了,所以要有第二次弹窗的效果,必须得在第一次成功之后再次让他加载js 代码: /*shaun*/showdetailsPag: funct ...

  6. 【PAT】B1060 爱丁顿数(25 分)

    逻辑问题,对我来说还是挺有难度的,一开始想不通 我输入数据并以数据为下标,数据出现次数为内容存储 然后从后遍历计算所有大于当前下标的元素出现的次数 最后遍历一遍确定是否为爱丁顿数,如果大于当前已经找到 ...

  7. February 4th, 2018 Week 6th Sunday

    Hope clouds observation. 心怀希望会蒙蔽双眼,影响判断. Almost every of us thinks we would be the master of our liv ...

  8. python scrapy爬虫框架概念介绍(个人理解总结为一张图)

    python的scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架   python和scrapy的安装就不介绍了,资料很多 这里我个人总结一下,能更加快理解scrapy和快速上手一个简 ...

  9. leetcode 44. Wildcard Matching(模糊匹配)

    搬运工了- - https://blog.csdn.net/jmspan/article/details/51460021

  10. msyql备份还原

    MySQL备份和还原,都是利用mysqldump.mysql和source命令来完成的. 1.Win32下MySQL的备份与还原 1.1 备份 开始菜单 | 运行 | cmd |利用“cd \Prog ...