\(NOI\) 网上同步赛

明白了身为菜鸡的自己和普通人的差距


DAY1

\(T1\) 轻重边

【题目描述】

小 W 有一棵 \(n\) 个结点的树,树上的每一条边可能是轻边或者重边。接下来你需要对树进行 \(m\) 次操作,在所有操作开始前,树上所有边都是轻边。操作有以下两种:

  1. 给定两个点 \(a\) 和 \(b\),首先对于 \(a\) 到 \(b\) 路径上的所有点 xx(包含 \(a\) 和 \(b\) ),你要将与 xx 相连的所有边变为轻边。然后再将 \(a\) 到 \(b\) 路径上包含的所有边变为重边。

  2. 给定两个点 \(a\) 和 \(b\) ,你需要计算当前 \(a\) 到 \(b\) 的路径上一共包含多少条重边。


撞题牛客付费题

不会正解。打了30分的暴力和20分的性质A,性质A是一条链,所以用线段树。

代码:
#include<bits/stdc++.h>
using namespace std;
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
return p*f;
}
const int N=1e5+5;
const int M=2e5+10;
int T,n,m;
struct edge{
int v,w,next;
}e[M];
int head[N],en=1;
void insert(int u,int v){
e[++en].v=v;
e[en].w=0;
e[en].next=head[u];
head[u]=en;
}
int fa[N][20],dep[N];
void dfs(int u,int f){
fa[u][0]=f;dep[u]=dep[f]+1;
for(int i=1;i<20;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(v==fa[u][0])continue;
dfs(v,u);
}
}
int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=19;i>=0;i--)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y)return y;
for(int i=19;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int gin[N];
int ntol[N],lton[N];
void dfsA(int u,int f){
ntol[u]=f;
lton[f]=u;
for(int i=head[u];i;i=e[i].next){
if(e[i].v==lton[f-1])continue;
dfsA(e[i].v,f+1);
}
}
//SGt---
int sum[4*N];
int tag[4*N];
void g(int l,int r,int p,int k){
tag[p]=k;
sum[p]=k*(r-l+1);
}
void pushdown(int l,int r,int p){
if(tag[p]){
int mid=(l+r)>>1;
g(l,mid,p<<1,tag[p]);
g(mid+1,r,p<<1|1,tag[p]);
tag[p]=0;
}
}
void pushup(int p){sum[p]=sum[p<<1]+sum[p<<1|1];}
void change(int l,int r,int p,int cl,int cr,int d){
if(cl>cr)return ;
if(l>=cl&&r<=cr){g(l,r,p,d);return ;}
pushdown(l,r,p);
int mid=(l+r)>>1;
if(cl<=mid)change(l,mid,p<<1,cl,cr,d);
if(cr>mid)change(mid+1,r,p<<1|1,cl,cr,d);
pushup(p);
}
int query(int l,int r,int p,int ql,int qr){
if(l>=ql&&r<=qr)return sum[p];
pushdown(l,r,p);
int mid=(l+r)>>1,res=0;
if(ql<=mid)res+=query(l,mid,p<<1,ql,qr);
if(qr>mid)res+=query(mid+1,r,p<<1|1,ql,qr);
return res;
}
//------
inline void clean(){
memset(fa,0,sizeof(fa));
memset(head,0,sizeof(head));
memset(gin,0,sizeof(gin));
memset(sum,0,sizeof(sum));
memset(tag,0,sizeof(tag));
en=1;
}
int main(){
freopen("edge.in","r",stdin);
freopen("edge.out","w",stdout);
T=in;
while(T--){
clean();
n=in,m=in;
if(n<=5000&&m<=5000){
for(int i=1;i<n;i++){
int u=in,v=in;
insert(u,v);
insert(v,u);
}
dfs(1,0);
for(int i=1;i<=m;i++){
int opt=in,a=in,b=in,c=lca(a,b);
if(opt==1){
int ta=a,tb=b;
while(a!=c){
for(int i=head[a];i;i=e[i].next)
if(e[i].v==fa[a][0]||e[i].v==ta)e[i].w=e[i^1].w=1;
else e[i].w=e[i^1].w=0;
ta=a,a=fa[a][0];
}
while(b!=c){
for(int i=head[b];i;i=e[i].next)
if(e[i].v==fa[b][0]||e[i].v==tb)e[i].w=e[i^1].w=1;
else e[i].w=e[i^1].w=0;
tb=b,b=fa[b][0];
}
for(int i=head[c];i;i=e[i].next)
if(e[i].v!=ta&&e[i].v!=tb)e[i].w=e[i^1].w=0;
}
else{
int ans=0;
while(a!=c){
for(int i=head[a];i;i=e[i].next)
if(e[i].v==fa[a][0]){
ans+=e[i].w;
break;
}
a=fa[a][0];
}
while(b!=c){
for(int i=head[b];i;i=e[i].next)
if(e[i].v==fa[b][0]){
ans+=e[i].w;
break;
}
b=fa[b][0];
}
printf("%d\n",ans);
}
}
}
else{
for(int i=1;i<n;i++){
int u=in,v=in;
insert(u,v);
insert(v,u);
gin[u]++,gin[v]++;
}
int s;
for(int i=1;i<=n;i++)
if(gin[i]==1)s=i;
dfsA(s,1);
for(int i=1;i<=m;i++){
int opt=in,a=in,b=in;
if(ntol[a]>ntol[b])swap(a,b);
a=ntol[a],b=ntol[b];
if(opt==1){
change(1,n,1,max(1,a-1),min(n-1,b),0);
change(1,n,1,a,b-1,1);
}
else{
int ans;
if(a==b)ans=0;
else ans=query(1,n,1,a,b-1);
printf("%d\n",ans);
}
}
}
}
return 0;
}

\(T2\) 路径交点

【题意翻译】

给定 \(n\) 个点 \(m\) 条边的有向无环图,其中没有入度的点被视为源点,没有出度的点被视为汇点,保证源点和汇点数目相同。

考虑所有把源汇点两两配对,并用两两不相交的路径把它们两两连接起来的所有方案。 如果这个方案中,把源点按标号1到n排序后,得到的对应汇点序列的逆序数对的个数是奇数,那么A给B一块钱,否则B给A一块钱。

问最后A的收益,对大质数取模。


撞题CF167E...现在出题都太卷了

正解是线代行列式,不会。

打了玄学暴力,期望10分。

代码:
#include<bits/stdc++.h>
using namespace std;
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
return p*f;
}
const int mod=998244353;
const int N=2e5+5;
const int M=4e6+5;
int T,k;
int n[105];
int m[105];
struct edge{
int v,next;
}e[M];
int head[N],en=1;
void insert(int u,int v){
e[++en].v=v;
e[en].next=head[u];
head[u]=en;
}
int q[205][105];
int ji,ou;
int vis[N];
void dfs(int x,int d,int sum){
if(x==n[1]&&d==k){
if(sum%2==1)ji=(ji+1)%mod;
else ou=(ou+1)%mod;
return ;
}
if(d==k)dfs(x+1,1,sum);
int u=q[x][d];
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(vis[v])continue;
int temp=0;
vis[v]=1;
q[x][d+1]=v;
for(int j=1;j<x;j++)
if((q[x][d]-q[j][d])*(q[x][d+1]-q[j][d+1])<0)temp++;
dfs(x,d+1,sum+temp);
vis[v]=0;
}
}
int main(){
freopen("xpath.in","r",stdin);
freopen("xpath.out","w",stdout);
T=in;
while(T--){
memset(head,0,sizeof(head));
en=ji=ou=0;
k=in;
for(int i=1;i<=k;i++)
n[i]=in;
for(int i=1;i<k;i++)
m[i]=in;
int t=0;
for(int i=1;i<k;i++){
for(int j=1;j<=m[i];j++)
insert(in+t,in+t+n[i]);
t+=n[i];
}
for(int i=1;i<=n[1];i++)
q[i][1]=i;
dfs(1,1,0);
printf("%d\n",(ou-ji+mod)%mod);
}
return 0;
}

\(T3\) 庆典

【题目描述】

C 国是一个繁荣昌盛的国家,它由 \(n\) 座城市和 \(m\) 条有向道路组成,城市从 \(1\) 到 \(n\) 编号。如果从 \(x\) 号城市出发,经过若干条道路后能到达 \(y\) 号城市,那么我们称 \(x\) 号城市可到达 \(y\) 号城市,记作 \(x\Rightarrow y\)。C 国的道路有一个特点:对于三座城市 \(x\),\(y\),\(z\),若 \(x\Rightarrow z\) 且 \(y\Rightarrow z\),那么有 \(x\Rightarrow y\) 或 \(y\Rightarrow x\)。

再过一个月就是 C 国成立的千年纪念日,所以 C 国的人民正在筹备盛大的游行庆典。目前 C 国得知接下来会有 \(q\) 次游行计划,第 \(i\) 次游行希望从城市 \(s_i\) 出发,经过若干个城市后,在城市 \(t_i\) 结束,且在游行过程中,一个城市可以被经过多次。为了增加游行的乐趣,每次游行还会临时修建出 \(k(0 \le k \le 2)\)条有向道路专门供本次游行使用,即其它游行计划不能通过本次游行修建的道路。

现在 C 国想知道,每次游行计划可能会经过多少座城市

注意:临时修建出的道路可以不满足 C 国道路原有的特点

【输入格式】

第一行包含四个整数 \(n\),\(m\),\(q\),\(k\),分别表示城市数、道路数、游行计划数以及每次游行临时修建的道路数。

接下来 \(m\) 行,每行包含两个整数 \(u\),\(v\),表示一条有向道路 \(u\rightarrow v\)。

接下来 q 行,每行前两个整数 \(s_i\),\(t_i\),表示每次游行的起点与终点;这行接下来有 \(k\) 对整数 \(a\),\(b\),每对整数表示一条临时添加的有向道路 \(a\rightarrow b\)。

数据保证,将 C 国原有的有向道路视为无向道路后,所有城市可以互达。


不会,神仙题。

想打个缩点+bfs暴力可是写挂了。0分。

代码:
#include<bits/stdc++.h>
using namespace std;
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
return p*f;
}
int s,t,n,m,q,k;
const int N=3e5+5;
const int M=6e5+5;
struct edge{
int v,next;
}e[M];
int head[N],en;
void insert(int u,int v){
e[++en].v=v;
e[en].next=head[u];
head[u]=en;
}
int dfn[N],low[N],df,vis[N],top,sta[N],sum,id[N],idw[N];
void dfs(int x){
dfn[x]=low[x]=++df;
sta[++top]=x;vis[x]=1;
for(int i=head[x];i;i=e[i].next){
int v=e[i].v;
if(!dfn[v]){
dfs(v);
low[x]=min(low[x],low[v]);
}
else if(vis[v]) low[x]=min(low[x],dfn[v]);
}
if(dfn[x]==low[x]){
int i=sta[top];
sum++;
idw[sum]=1;
while(i!=x){
idw[sum]++;
id[i]=sum;
vis[i]=0;
i=sta[--top];
}
id[i]=sum;
vis[i]=0;
--top;
}
}
struct Edge{
int v,next;
}E[M];
int Head[N],En;
void Insert(int u,int v){
E[++En].v=v;
E[En].next=Head[u];
Head[u]=En;
}
int que[90000005];
int pre[90000005];
int qh=0,qt=0;
int ans;
int bfs(int s,int t){
int res=0;
qh=qt=0;
que[++qt]=s,pre[qt]=0;
while(qh<qt){
qh++;
int u=que[qh];
if(u==t){
int now=qh;
while(pre[now]!=0){
res+=idw[que[now]];
idw[que[now]]=0;
now=pre[now];
}
res+=idw[que[now]];
idw[que[now]]=0;
}
for(int i=Head[u];i;i=E[i].next){
int v=e[i].v;
que[++qt]=v,pre[qt]=qh;
}
}
return res;
}
inline void clean(){
memset(Head,0,sizeof(Head));
memset(vis,0,sizeof(vis));
memset(idw,0,sizeof(idw));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
En=ans=df=sum=0;
}
int temp[5];
void del(int u){
head[u]=e[en].next;
en--;
}
int main(){
freopen("celebration.in","r",stdin);
freopen("celebration.out","w",stdout);
n=in,m=in,q=in,k=in;
for(int i=1;i<=m;i++)
insert(in,in);
for(int i=1;i<=q;i++){
clean();
s=in,t=in;
for(int i=1;i<=k;i++){
temp[i]=in;
insert(temp[i],in);
}
for(int i=1;i<=n;i++)
if(!dfn[i])dfs(i);
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=e[j].next)
if(id[i]!=id[e[j].v])Insert(id[i],id[e[j].v]);
s=id[s],t=id[t];
printf("%d\n",bfs(s,t));
for(int i=1;i<=k;i++)
del(temp[i]);
}
return 0;
}

T1线段树写挂了,以后tag全部清-1,不能清0...

T2暴力成功。

T3不出预料地抱铃。

day1=30+30+0=60


DAY2

T1 量子通信

暴力。好多人用随机算法,不会。。。

代码:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
//题意putin-------------------------------------------
const int N = 400000;
bool s[N+1][256];
ull myRand(ull &k1, ull &k2) {
ull k3 = k1, k4 = k2;
k1 = k4;
k3 ^= (k3 << 23);
k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
return k2 + k4;
} void gen(int n, ull a1, ull a2) {
for (int i = 1; i <= n; i++)
for (int j = 0; j < 256; j++)
s[i][j] = (myRand(a1, a2) & (1ull << 32)) ? 1 : 0;
}
//-----------------------------------------------------
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c<='9'&&c>='0'){p=p*10+c-'0';c=getchar();}
return p*f;
}
int n,m;
ull a1,a2;
bool a[256];
int ans;
signed main(){
freopen("qi.in","r",stdin);
freopen("qi.out","w",stdout);
cin>>n>>m>>a1>>a2;
gen(n,a1,a2);
for(int g=1;g<=m;g++){
string c;
int k,flag=0;
cin>>c>>k;
for(int i=0;i<64;i++){
int t;
if(c[i]>'9'||c[i]<'0')t=c[i]-'A'+10;
else t=c[i]-'0';
for(int j=3;j>=0;j--){
a[i*4+j]=(t%2)^ans;
t/=2;
}
}
for(int i=1;i<=n;i++){
int t=0;
for(int j=0;j<256;j++){
if(a[j]!=s[i][j])t++;
if(t>k)break;
}
if(t<=k)flag=1;
}
ans=flag;
printf("%d\n",ans);
}
return 0;
}

T2 密码箱

打了一个平衡树,调了半场比赛,还写挂了?

矩阵是真想不到。

代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=200005;
const int mod=998244353;
inline int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c<='9'&&c>='0'){p=p*10+c-'0';c=getchar();}
return p*f;
}
struct node{
int v;
int fa;
int ch[2];
int siz;
int rev;
int filp;
}a[maxn];
int rt,tot,n,m;
int w[maxn];
inline void pushup(int x){
a[x].siz=a[a[x].ch[0]].siz+a[a[x].ch[1]].siz+1;
}
inline void pushdown(int x){
if(a[x].rev){
a[x].rev=0;
a[a[x].ch[0]].rev^=1;
a[a[x].ch[1]].rev^=1;
swap(a[x].ch[0],a[x].ch[1]);
}
if(a[x].filp){
a[x].filp=0;
if(a[x].v)a[x].v=3-a[x].v;
a[a[x].ch[0]].filp^=1;
a[a[x].ch[1]].filp^=1;
}
}
inline void rotate(int x){
int y=a[x].fa,z=a[y].fa,d=(a[y].ch[1]==x);
pushdown(y);pushdown(x);
a[y].ch[d]=a[x].ch[d^1];
a[a[y].ch[d]].fa=y;
a[x].ch[d^1]=y;a[y].fa=x;
a[x].fa=z;
if(z){
if(y==a[z].ch[1])a[z].ch[1]=x;
else a[z].ch[0]=x;
}
pushup(y);
pushup(x);
}
inline void splay(int x,int g){
for(;a[x].fa!=g;rotate(x))
if(a[a[x].fa].fa!=g) rotate(((x==a[a[x].fa].ch[1])==(a[x].fa==a[a[a[x].fa].fa].ch[1]))?a[x].fa:x);
if(g==0)rt=x;
}
inline int newnode(int x,int fa){
a[++tot].fa=fa;
a[tot].v=x;
a[tot].siz=1;
a[tot].rev=a[tot].filp=0;
return tot;
}
inline int built(int l,int r,int fa){
if(l>r)return 0;
int mid=(l+r)>>1;
int x=newnode(w[mid],fa);
a[x].ch[0]=built(l,mid-1,x);
a[x].ch[1]=built(mid+1,r,x);
pushup(x);
return x;
}
inline int find(int x){
int now=rt;
while(true){
pushdown(now);
if(x==a[a[now].ch[0]].siz+1)return now;
else if(x<a[a[now].ch[0]].siz+1)now=a[now].ch[0];
else{x-=a[a[now].ch[0]].siz+1;now=a[now].ch[1];}
}
}
inline void reverse(int l,int r){
int pre=find(l-1),nxt=find(r+1);
splay(pre,0);splay(nxt,pre);
int now=a[nxt].ch[0];
a[now].rev^=1;
}
inline void filp(int l,int r){
int pre=find(l-1),nxt=find(r+1);
splay(pre,0);splay(nxt,pre);
int now=a[nxt].ch[0];
a[now].filp^=1;
}
inline void insert(int x){
int pre=find(n+1),nxt=find(n+2);
splay(nxt,0);splay(pre,nxt);
a[pre].ch[1]=newnode(x,pre);
pushup(pre),pushup(nxt);
}
int tc,cz[maxn];
inline void out(int p){
if(!p)return;
pushdown(p);
out(a[p].ch[0]);
if(a[p].v!=0)cz[++tc]=a[p].v;
out(a[p].ch[1]);
}
int top,q[2*maxn+20];
int mul(int x,int y){return x*y%mod;}
int add(int x,int y){return (x+y)%mod;}
struct fenshu{
int fz,fm;
};
int gcd(int a,int b){return b?gcd(b,a%b):a;}
fenshu operator+(const fenshu &x,const fenshu &y){
fenshu z;
z.fm=mul(x.fm,y.fm);
z.fz=add(mul(x.fz,y.fm),mul(y.fz,x.fm));
int t=gcd(z.fm,z.fz);
z.fm/=t,z.fz/=t;
return z;
}
void work(){
top=0;
q[++top]=0,q[++top]=1;
for(int i=1;i<=tc;i++){
if(cz[i]==1)q[top]++;
else{
if(q[top]==1)q[top-1]++;
else q[top]--,q[++top]=1,q[++top]=1;
}
}
tc=0;
fenshu ans;ans.fm=1,ans.fz=q[top];
for(int i=top-1;i>=1;i--){
swap(ans.fm,ans.fz);
fenshu temp;temp.fm=1;temp.fz=q[i];
ans=ans+temp;
}
cout<<ans.fz<<" "<<ans.fm<<'\n';
return ;
}
signed main(){
// freopen("code.in","r",stdin);
// freopen("code.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=n;i++){
char c;cin>>c;
w[i]=(c=='W')?1:2;
}
built(0,n+1,0);rt=1;
out(rt);
work();
for(int i=1;i<=m;i++){
char s[11];
cin>>s;
if(s[0]=='A'){char c;cin>>c;insert((c=='W')?1:2);n++;}
else if(s[0]=='F'){int l=read(),r=read();filp(l+1,r+1);}
else if(s[0]=='R'){int l=read(),r=read();reverse(l+1,r+1);}
out(rt);
work();
}
return 0;
}

T3 机器人游戏

把n=1且m=1分析了一下。

小D几毫秒就能做的我都做不来,更不要说小D不会的。

代码:
#include<bits/stdc++.h>
using namespace std;
int n,m;
string s[1005];
const int mod=1e9+7;
signed main(){
freopen("robot.in","r",stdin);
freopen("robot.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>s[i];
if(s[1][0]=='0'||s[1][0]=='1'||s[1][0]=='*')cout<<3;
else cout<<1;
return 0;
}

d2t2平衡树写挂了,以后再不碰Splay。

day2=20+0+8=28


NOI2021=30+30+0+20+0+8=88

写挂的有点多,d1t1写挂20,d1t3多花点时间可能是有 \([16,28]\) 的,d2t2也写挂20。


大概再发挥好点能有个场外Cu。果然我是菜鸡啊。

最新文章

  1. request 对象和 response 对象
  2. 微信公众平台实现pc端网站登录
  3. JAVA 基本运算符(摘)
  4. CodeForces 616D Longest k-Good Segment
  5. jwt token Example - Python
  6. 媒体查询media参数以及其兼容性问题
  7. [转]nodejs日期时间插件moment.js
  8. Elasticsearch学习笔记(十四)relevance score相关性评分的计算(1)
  9. Spring Boot与Docker部署
  10. Vue之变量、数据绑定、事件绑定使用举例
  11. Niagara workbench 介绍文档---翻译
  12. Cortex-A15架构解析:它为什么这么强(转)
  13. android程序----&gt;android多线程下载(二)
  14. ML(4.3): R Random Forest
  15. css四种选择器总结
  16. GDAL VS2010 win7(64位)安装、使用说明(图文解析)
  17. DevExpress02、RibbonControl
  18. 【Anroid】9.1 ListView相关类及其适配器
  19. 2017北京国庆刷题Day5 morning
  20. 使用内省的方式操作JavaBean

热门文章

  1. golang 判断平台是32位还是64位
  2. Markdown主要语法及使用
  3. 一文彻底搞懂Hive的数据存储与压缩
  4. 修改 CubeMX 生成的 RT-Thread makefile 工程
  5. 深入学习Composer原理(二)
  6. 优雅地创建未定义类PHP对象
  7. Java基础系列(35)- 数组声明创建
  8. 如何理解 jmeter 的线程数与并发数之间的关系
  9. mac php安装扩展 如 seoole apcu
  10. JDBC封装的工具类