以下所有代码为自己xjb写的,不确定对不对,如果有重现赛,可以交一交
后续:7月23号重现赛,都交了一下,发现都可以过,mdzz
本次邀请赛,说明我们队还是离邀请赛金或者区域赛稳银还是有很大的距离的,
一方面,是暴露出的种种的不足;另一方面,可能需要反思的是平时的学习模式的问题
毕竟在ACM的道路上,还是有种种不利因素,阻止着变强啊
AD水题,B是大模拟没写出来,
C是一个类似康托展开的魔改,
在允许字母可重的情况下,对字符串s(|s|<=16)全排列之后去重,询问第k大的排列
一开始敲了一发康托展开的板子,打表输出了一些奇奇怪怪不按字典序出牌的东西
后来被归神指出重复排列会被当成两个,卡了会之后想到了枚举这一位填什么字母,增序枚举,
所在的rank区间[L,R],如果[L,R]包含k就填这一位,否则就加上这段rank,再往大里填
然而写了1个小时,回宾馆调了调调过样例了也不知道对不对
当然,写一半的时候,主办方说BC数据出锅了,不然那么多金爷怎么可能做不出来
#include
using namespace std;
typedef long long ll;
bool flag;
char ans[20],s[20];
int now[26],len;
ll A[20],p,tmp,rk;
int main()
{
A[0]=1;
for(int i=1;i<=16;++i)
A[i]=A[i-1]*i;
while(~scanf("%s%lld",s,&p))
{
if(s[0]=='#'&&!p)break;
len=strlen(s);
memset(now,0,sizeof now);
rk=1;
for(int i=0;i
槽,正赛有三份英文题面一份中文题面是什么鬼
L题,直接输出5个数,2min1Y,我也想0min1Y啊,然而找到这个题敲完就2min了
K题,a[i]的前缀和,排个增序,小的对应乘小的,排序不等式和最大,输出这个和,归神单开,7min1y
F题,1e5个数,1e5个询问,两种操作,一个单点改数,另一个询问[L,R],
其每个L<=l<=r<=R的子区间(l,r)的贡献定义为这个子区间所有值的异或,求[L,R]内所有子区间的贡献的异或
涛神率先提出的思路,统计每个值被计了多少次,是(i-l+1)*(r-i+1)次,然后分l和r是否同奇偶讨论,
如果同奇偶,再分i是否和l、r同奇偶讨论,奇数位置开一棵线段树,偶数位置开一棵线段树
归神的线段树写了点小bug,我跟着调出来了,39min1y,
想了想BIT也可以维护区间异或,觉着要是敲着更熟练的话,时间可以更短,赛后试了下的确如此
看了一下榜,J题和G题各有几个队过,我开了J,归神看了G
J是一个裸的字典树,1e5个串,串总长小于2e5,每个小写字母对应一个hash值,
整个串的hash值是所有字母hash值的乘积%m,对于每个串问有多少前缀满足在模意义下,hash值比整个串小,
我约20分钟敲了个板子然而结果不对,归神这时候G有了思路先让他敲G,我只好打印代码debug,
后来发现,先是数组重名了,然后自己令rt=1结果开节点还在tot=0的情况下++tot,写好这里之后90min1y了,
的确是因为自己板子的问题,没能更快的1y,要整理一个好的字典树板子①
G题是一个贪心叭,1e5个人,每个人有三个权值ai,bi,ci,
题目保证ai两两不同,bi,ci同理,只要有一个权值比另一个人的对应权值大,这个人就可以赢另一个,
要举办n-1场比赛,主办方每次可以指定两个未淘汰选手,指定用哪个权值进行比较,
最后1e5个询问,询问每个人是否能成为冠军
首先,三个权值分别最大的人ABC是能成为冠军的,也因此更新了他们在别的领域的最小值,
如果D能战胜这些最小值的一个,就能让那个人先把n-2个人扫了之后,再最后一轮输给D,
所以就是不断更新最小值至不能再更新
归神提了一个按值更新的做法,RE了一发又WA了一发,这个时候我们想听思路,我问涛神涛神也没听懂,
涛神后来懂了帮归神debug,说两个人懂了就没必要再讲了,我就去新开题了,
我在这一个多小时是挂机的,想跟榜但是榜过别的题的人寥寥无几只有两三个,
然而归神心态有点崩,又分别WA和RE了一发,177min5y
看了一下榜,5题罚时404rank81,已经有八九十个队伍是五题及以上了,
且如果少一发罚时的话,能前进约10名左右,诶,又是一个罚时局
后两个小时就很无力了,一方面是有中餐之后代码输出力--(麦当劳中餐好评呀,感觉中餐投入得是其它赛区的两倍)
另一方面也是后期题我们知识重合的部分比较少,在配合方面,还有很多不足
我开了H题,涛神开了B题,期间也看过A题、D题和E题,
A题想过用费用流,但不会处理多次通过这条边只记录一次流量,赛后才知道竟然是斯坦纳树裸题……
看完几个题之后,感觉可能能做的也就B和H
涛神看了一会B题发现不会做,我跟着看了一会,提出如果能求就好了,然而仨人都不会求,
而且高斯消元的复杂度O(n^3)在这里解n=1e3的式子很拙计,更何况大家都只是天天口胡并没有套过板子
赛后才知道是裸的拉格朗日差值,而且我收藏夹里有拉格朗日差值,例题就是求这个式子,槽
我看了H题,发现前半部分是裸的FWT抄了一发板子,然而后半部分被我理解错了题意(背锅)
神奇的是,我在做这个题的时候对面电子科大的dove队9发破I之后也在搞这个题,
而且进度近乎和我一致,然而他们最后1h也没能过这个题,估计也是读错题了
是对FWT之后的序列维护两种操作,一种是[l,r]内暴力开根,另一种是询问位置x的值,
我当时以为开根完之后数变小会跑到前面去,赛后看知乎也有中学生和我理解的一样,用的splay,槽
然后我就和归神在那里敲权值线段树,每次暴力开[l,r]区间然后忽视已经值是1的部分,
我自己权值线段树敲被理解错的这题估计也需要2h,归神也坦言说自己可能也需要2h敲,
一方面是第五题导致时间不太够,另一方面也的确是大家的后期输出力可能还有待提升
然而开根之后的数的位置是不变的,于是就变成了二分位置之后一个离散化+线段树区间覆盖的板子题
另一方面,虽然我和归神都能手敲区间覆盖,但感觉这种板子还是要有的,毕竟赛场争分夺秒,不容出错
现在觉得也是最后一个小时大家都不大稳叭,
我那个时候固执地觉得是位置移动的,涛神也直接说自己挂机了,
就感觉仨人的状态都有下降吧,如果能完整地手跑一下样例,应该是能区别出这种情况的
赛后去请教山东理工大学过这个题的队伍解法之后,感觉不读错题的情况下,应该是可以1h调出来的
不过赛后也证明,我们的罚时自第五题之后连交第六题AC也不能金了,所以可能没什么好遗憾的,菜就完事了
5题银到铁,滚榜的时候看那个罚时一会1分钟2分钟的往前减一会掉七八分钟当时觉得很有可能是铜,
结果,rk81最后掉到rk85,算是捡了个银牌倒数叭,诶如果能过第六题,哪有这么多需要担忧的
一方面说明大家的水平可能差不多,另一方面也说明,在做中期题这方面,我们还是不如其他学校
喔,顺便一提,F题和J题好像是数据出锅了,被某些队伍F暴力/J两个map卡过去了
赛后逛知乎发现,I题是一个优雅的暴力的思维题,只是因为没人开;
C题欧拉降幂+dp,可补,但的确也是因为榜上过题人数少,没开
从个人方面分析一下自己可能存在的不足吧,有则改之,无则加勉
①思维题训练量不够
在这方面,CF还是利于培养思维,10多场和100多场的区别,高下立判
②赛后不补题的坏习惯
这个就不用多说了,蒟蒻ACMER的通病
③口胡题解之后不注重代码实现
AC is OK,其他都是0
④互膜的不良风气
可能这是高中OIER圈也存在的风气吧,只有自己内心深处,才知道自己多菜吧
⑤过题之后水群炫耀
多过题,少水群,少吹比,很多知识,只有自己不会
⑥刷水题寻找满足感
还是要走出自己的comfort zone叭,Claris也曾说过,只有做自己不会的题才会有提升
⑦学习新知识时死抠原理
这也是自己上学期只学知识不做题的弊病叭,更重要的是应用
⑧学知识时找偏难怪得学
有些知识学了之后八百年也不一定考一次,考的时候可能都不记得自己学过了
区域赛后期题也往往不会出裸题,邀请赛这种是特例
⑨因为知识名字比较怪望而生畏
犹记得自己嚷嚷着学启发式合并到现在还没有学,拉格朗日插值至今躺在收藏夹里或许也是这个原因吧……
少从队友身上找理由,多从自己身上找不足,你是主代码手呀!
A题
#include
using namespace std;
/*
* Steiner Tree:求,使得指定K个点连通的生成树的最小总权值
* st[i] 表示顶点i的标记值,如果i是指定集合内第m(0<=m que;
mapmp;
string rd1,rd2;
void add(int u,int v,int w)
{
V[++cnt]=v;
W[cnt]=w;
nex[cnt]=head[u];
head[u]=cnt;
}
void initSteinerTree()
{
mp.clear();
num=cost=0;
cnt=0;
memset(head,0,sizeof head);
memset(dp,-1,sizeof dp);
memset(ans,-1,sizeof ans);
memset(st,0,sizeof st);
for(int i=1;i<=n;i++)
memset(vis[i],0,sizeof vis[i]);
//对每个st[i]赋值 对endSt赋值
}
void input()
{
for(int i=1;i<=n;++i)
{
cin>>rd1;
mp[rd1]=i;
}
for(int i=1;i<=m;++i)
{
cin>>rd1>>rd2>>cost;
u=mp[rd1],v=mp[rd2];
add(u,v,cost);
add(v,u,cost);
}
for(int i=0;i<4;++i)
{
cin>>rd1>>rd2;
u=mp[rd1];v=mp[rd2];
st[u]|=1<x || a==-1)? x : a;
}
void SPFA(int state)
{
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u][state]=false;
for(int i=head[u];i;i=nex[i])
{
int v=V[i];//以v为根 不管v不是所选集合节点还是是
if(dp[v][st[v]|state]==-1 || dp[v][st[v]|state]>dp[u][state]+W[i])
{
dp[v][st[v]|state]=dp[u][state]+W[i];
if(st[v]|state!=state || vis[v][state])continue; //只用当前state更新所有根节点i的dp[i][state]的最小值
vis[v][state]=true;
que.push(v);
}
}
}
}
void steinerTree()
{
for(int j=1;j>i&1)res^=(1<>i&1)res^=(1<<(i-4));
return res==0;
}
void solve()
{
for(int j=1;j>n>>m)
{
initSteinerTree();
input();
steinerTree();
solve();
}
return 0;
}
B题
#include
using namespace std;
typedef long long ll;
const int mod=9999991;
const int N=1e3+10;
int t,n,m,l,r;
int a[N],sum[N],pre[N],suf[N];
int fac[N],finv[N];
int modpow(int x,int n,int p)
{
int res=1;
for(;n;x=1ll*x*x%p,n>>=1)
if(n&1)res=1ll*res*x%p;
return res;
}
int cal(int *f,int mx,int n)//已知f[0]到f[mx] 求f[n]
{
if(n<=mx)return f[n];
int ans=0;
pre[0]=suf[mx]=1;
for(int i=1;i<=mx;++i)
pre[i]=1ll*pre[i-1]*(n-i+1)%mod;
for(int i=mx;i>=1;--i)
suf[i-1]=1ll*suf[i]*(n-i)%mod;
for(int i=0;i<=mx;++i)
{
int sg=(mx-i)&1?-1:1;
ans=ans+1ll*sg*pre[i]%mod*suf[i]%mod*finv[i]%mod*finv[mx-i]%mod*f[i]%mod;
if(ans>=mod)ans-=mod;
if(ans<0)ans+=mod;
}
return ans;
}
void init()
{
fac[0]=1;
for(int i=1;i=1;--i)
finv[i-1]=1ll*finv[i]*i%mod;
}
int main()
{
init();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)
scanf("%d",&a[i]);
a[n+1]=cal(a,n,n+1);//插出f(n+1)
sum[0]=a[0];//非常关键 别忘了
for(int i=1;i<=n+1;i++)
sum[i]=(sum[i-1]+a[i])%mod;
while(m--)
{
scanf("%d%d",&l,&r);
int cnt=cal(sum,n+1,r)-cal(sum,n+1,l-1);
if(cnt<0)cnt+=mod;
printf("%d\n",cnt);
}
}
return 0;
}
C题
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int p=1e5+3;
const int maxn=1e5+10;
const int N=1e5+10;
const int M=5e3+5;
bool ok[maxn];
int prime[maxn],phi[maxn],cnt;
int a,b,n;
int u[N],v[N];
int dp[2][M][2];
void sieve()
{
phi[1]=1;
for(ll i=2;i=maxn)break;
ok[i*prime[j]]=1;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];//prime[j]是i的因子 prime[j]的素因子项包含在i的素因子项里
break;
}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);//prime[j]与i互质 phi[i*prime[j]=phi[i]*phi[prime[j]]
}
}
}
int modpow(int x,int n,int mod)
{
int ans=1;
for(;n;n/=2,x=1ll*x*x%mod)
if(n&1)ans=1ll*ans*x%mod;
return ans;
}
int f(int num,int mod)
{
if(mod==1)return 0;
if(num==1)return b%mod;
return modpow(b,f(num-1,phi[mod])+phi[mod],mod);
}
int main()
{
sieve();
while(~scanf("%d%d",&a,&b))
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&u[i]);
u[i]=modpow(a,f(u[i],phi[p])+phi[p],p);
}
for(int i=1;i<=n;++i)
{
scanf("%d",&v[i]);
v[i]=modpow(a,f(v[i],phi[p])+phi[p],p);
}
memset(dp,0,sizeof dp);
u[0]=v[0]=p+1;//保证和第二项不同
for(int k=0;k<=n;++k)
{
int i=k&1;
for(int j=0;j<=n;++j)
{
dp[i][j][0]=0;
dp[i][j][1]=0;
}
for(int j=0;j<=n;++j)
{
if(k>0)
{
dp[i][j][0]=max(dp[i][j][0],dp[i^1][j][0]+u[k]*(u[k]==u[k-1]));
dp[i][j][0]=max(dp[i][j][0],dp[i^1][j][1]+u[k]*(u[k]==v[j]));
}
if(j>0)
{
dp[i][j][1]=max(dp[i][j][1],dp[i][j-1][0]+v[j]*(v[j]==u[k]));
dp[i][j][1]=max(dp[i][j][1],dp[i][j-1][1]+v[j]*(v[j]==v[j-1]));
}
}
}
printf("%d\n",max(dp[n&1][n][0],dp[n&1][n][1]));
}
return 0;
}
F题
#include
using namespace std;
const int maxn=1e5+10;
int tr[2][maxn],a[maxn];
int t,n,m;
int op,l,r;
void add(int *a,int x,int v)
{
for(int i=x;i<=n;i+=i&-i)
a[i]^=v;
}
int Xor(int *a,int x)
{
int ans=0;
for(int i=x;i>0;i-=i&-i)
ans^=a[i];
return ans;
}
int main()
{
scanf("%d",&t);
for(int cas=1;cas<=t;++cas)
{
memset(tr,0,sizeof tr);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
if(i&1)add(tr[0],i,a[i]);
else add(tr[1],i,a[i]);
}
printf("Case #%d:\n",cas);
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&op,&l,&r);
if(!op)
{
if(l&1)add(tr[0],l,a[l]),add(tr[0],l,r);
else add(tr[1],l,a[l]),add(tr[1],l,r);
a[l]=r;
continue;
}
if((r-l)&1){puts("0");continue;}
else
{
if(l&1)printf("%d\n",Xor(tr[0],r)^Xor(tr[0],l-1));
else printf("%d\n",Xor(tr[1],r)^Xor(tr[1],l-1));
}
}
}
return 0;
}
G题
#include
using namespace std;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
struct node
{
int v,id;
node(){}
node(int vv,int i):v(vv),id(i){
}
}tmp;
bool operator<(node a,node b)
{
return a.vp[3];
int mn[3],a[3][maxn];
int n,q,v;
bool ok[maxn],flag;
int main()
{
for(int i=0;i<3;++i)
mn[i]=INF;
scanf("%d%d",&n,&q);
for(int j=0;j<3;++j)
{
for(int i=1;i<=n;++i)
{
scanf("%d",&a[j][i]);
p[j].push(node(a[j][i],i));
}
}
for(int i=0;i<3;++i)
{
tmp=p[i].top();p[i].pop();
ok[tmp.id]=1;
mn[i]=min(mn[i],a[i][tmp.id]);
mn[(i+1)%3]=min(mn[(i+1)%3],a[(i+1)%3][tmp.id]);
mn[(i+2)%3]=min(mn[(i+2)%3],a[(i+2)%3][tmp.id]);
}
flag=1;
while(flag)
{
flag=0;
for(int i=0;i<3;++i)
{
while(!p[i].empty()&&p[i].top().v>mn[i])
{
tmp=p[i].top();p[i].pop();
if(ok[tmp.id])continue;
ok[tmp.id]=1;flag=1;//代表本次更新有人被取出
mn[(i+1)%3]=min(mn[(i+1)%3],a[(i+1)%3][tmp.id]);
mn[(i+2)%3]=min(mn[(i+2)%3],a[(i+2)%3][tmp.id]);
}
}
}
for(int i=1;i<=q;++i)
{
scanf("%d",&v);
puts(ok[v]?"YES":"NO");
}
return 0;
}
H题
#include
using namespace std;
typedef long long ll;
const int maxn=3e5+5;
const int maxm=1e5+5;
int n,m;
ll x[maxn],y[maxn];
ll dat[maxn*5],cov[maxn*5];
ll a[maxn],b[maxn],N,mx,v;
ll num[maxn],cnt,tot;
ll in[maxn],cal;
ll sum[maxn];
struct node
{
ll x,y,id;
ll tox,toy;
node(){}
node(ll xx,ll yy,ll p):x(xx),y(yy),id(p){}
}e[maxm];
void pushup(int p)
{
dat[p]=dat[p<<1]+dat[p<<1|1];
}
void pushdown(int p,int l,int r)
{
if(cov[p])
{
int mid=l+r>>1;
cov[p<<1]+=cov[p];
dat[p<<1]+=cov[p]*(mid-l+1);
cov[p<<1|1]+=cov[p];
dat[p<<1|1]+=cov[p]*(r-mid);
cov[p]=0;
}
}
void update(int p,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
{
dat[p]+=r-l+1;
cov[p]++;
return;
}
pushdown(p,l,r);
int mid=l+r>>1;
if(ql<=mid)update(p<<1,l,mid,ql,qr);
if(qr>mid)update(p<<1|1,mid+1,r,ql,qr);
pushup(p);
}
int ask(int p,int l,int r,int pos)
{
if(l==r)return dat[p];
pushdown(p,l,r);
int mid=l+r>>1;
if(pos<=mid)return ask(p<<1,l,mid,pos);
else return ask(p<<1|1,mid+1,r,pos);
}
void FWT_or(ll *a,int op)
{
for(int i=1;i6){puts("1");continue;}
for(int j=1;j<=res;++j)
c=sqrt(c);
printf("%lld\n",c);
}
else update(1,1,tot,e[i].tox,e[i].toy);
}
return 0;
}
/*
5
6 2 6 4 5
1 7 9 10 3
5
17 21
0 8
8 13
0 8
0 20
*/