icpc沈阳站记录
2021.11.22凌晨
从昨晚紧张到辗转反侧,虽然早就做好了打铁的心理准备,但待到比赛最后一刻两道铜牌题还没出时,满脑子的不甘心。当然最后肯定铁了395/576。
11.21也就是热身赛那天,和队友做好了一切准备,板子,战术,再到心理,u1s1赛前,我们还是很有信心拿牌的。赛前两周的训练,我们的训练重点就是手速签到和铜牌题,训练的时候基本稳铜,甚至常能超过以前现场赛的师兄。唉,做这么多到如今看来也确是有点可笑,因为比赛只看结果,说难听点,铁了那你的训练说白了都是低效。
复盘一下我们的比赛,两道水题稳扎稳打check几遍然后1a,此时还是rank210多左右,这时其实排名不重要,因为两个水题大家罚时差不多。
我和唐看b,吴看j,我跟唐说了下异或的传递性,唐说了下图论然后我们就往图上想,一开始没太注意异或的性质,假了最小生成树和换根dp,此时时间已经来到三个半小时了,这一切都建立在默认一个联通块里一定存在一个点为0,好了我开始演了,写了发字典树自己发现假了,下机,队友写了j的分类讨论jwa了,下机,我发现不用字典树直接数组统计就行,写一发wa了,距离结束还剩半小时,绝望!
当时觉得自己思路无敌对,队友讨论的j也写了很多ifelse,都困在自认为无敌对的窘境。最后半小时简直折磨,直到最后一刻打铁的宣判。。。

赛后发现我的b假了,一个块不一定以有0最优,我只是看到了局部相邻点最优。因为异或的性质,联通块里一个点确定了,所有点都确定了,所以我们枚举任意一个点某一位取0/1即可。
j题我输得心服口服,一个数位码问题转化成bfs做,我们真的想不到,四题铜,就算出了b,我们也会被j拦了。其实看完j后,觉得j数据范围这么小,应该是道网络流题,反正按题目模拟要考虑的情况太多了。但是因为之前做过一道类似的简单一点的分类讨论,我们觉得应该可以写出来,也就没往图上想。
唉,感觉两个铜牌题思考量不小,偏思维,日后要加强思维训练!

团队合作上,我感觉我的思路可能跟队友没讲清楚,导致没有发现我假的贪心。。。。

其他杂谈:学了快一年的算法了,严格来说是十一个月,一千出头一点的题量,回首我的战绩还是菜的抠脚,cf还没蓝,还是跟大佬们差距悬殊,依旧只能签到,出不了铜牌题。。。。但是再和过往的自己比较,从学语法时候关于void的意义各种查资料,再到学刚算法入门时听个线段树果断挂机了,再到一道线段树调三天。。。现在也会很多算法的板子了,以及在数论带给我的折磨中,学到了许多数学知识。我想说,我不甘心打铁,我也不遗憾打铁,因为还没拿铜的实力,如果真有铜的实力,跟榜出4题拿铜稳的。难受是一时,后面还是得针对性训练,明年加油。

11.23
过了一天好像也没那么难受了,如果我这cf都没上蓝名的fw能拿牌,那多少逆天了(
临近期末月了,准备预习书本知识TwT.
记录下这次刻苦铭心的打铁记录,警示自己。

2333顺便把题解随手写了

B题上面大概说了一下
再说一下,我们任意找个点dfs一下,假设找的是点x,就能得到x所在连通块里所有点到它的距离,现在就是确定下x的值,那块里所有点都能确定了。
(二进制下)若x的第i位取0,假设块里其他所有距离中第i位为1的数量为cnt,则块里所有数的第i位对sum的贡献为 2cnt2^{cnt}2cnt,若取1,则贡献为2tot−cnt2^{tot-cnt}2tot−cnt(tot为块大小),唉现在想想就是简单的贪心,当时怎么就固执的认为取0最优呢T - T

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cstring>
#include<string>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define int long long
using namespace std;
const int N=1e5+5,M=2e5+5;
const long long INF=0x7f7f7f7f7f7f7f7f;
int n,m;
struct B{long long u,v,w;
}a[M*4];long long pi,p[N],nxt[M*4],to[M*4],cost[M*4];
bool vis[N];
long long che[N];
long long val[N];
struct Dij{long long t,value;friend bool operator <(Dij i,Dij j){return i.value>j.value; }
};
void add_in(long long u,long long v,long long c)
{pi++;nxt[pi]=p[u];p[u]=pi;to[pi]=v;cost[pi]=c;
}
int  cnt[40][2];
void build(int x)
{for(int i=30 ;i>=0 ;i--){int k = (x>>i)&1;cnt[i][k]++;}
}
void ini()
{for(int i=0 ;i<=30 ;i++) cnt[i][0] = cnt[i][1]=0;
}
vector<int > v;
int work()
{int ans=0;int siz = v.size();
//  for(int i:v) cout<<i<<" ";//cout<<endl;for(int i=30 ;i>=0 ;i--){// cout<<i<<" i "<<cnt[i][0]<<" "<<cnt[i][1]<<endl;ans += (1ll<<i)*((min(cnt[i][0],cnt[i][1])));}return ans;
}
bool check_(int s)
{ini();v.clear();vis[s]=true;che[s]=0;queue<int> q;
//  cout<<" s "while(!q.empty())q.pop();q.push(s);while(!q.empty()){int u=q.front();q.pop();build(che[u]);v.push_back(che[u]);for(int k=p[u],v=to[k],c=cost[k];k;k=nxt[k],v=to[k],c=cost[k]){if(!vis[v]){vis[v]=true;che[v]= (che[u]^c);q.push(v);}else{if( (che[v]^che[u] )!=c){//     cout<<" v "<<che[v]<<" "<<che[u]<<" "<<c<<endl;return false;}}}}return true;
}
signed main()
{IOS;cin>>n>>m;for(int i=1;i<=m;i++){int u,v,c;cin>>u>>v>>c;add_in(u,v,c);add_in(v,u,c);}int ans=0;for(int i=1;i<=n;i++){if(!vis[i]){if(!check_(i)){cout<<"-1";return 0;}
//              for(int i=1;i<=n;i++)
//           cout<<che[i]<<' '; ans += work();//cout<<ans<<endl;}}
//  cout<<" ans "<<endl;cout<<ans<<endl;return 0;
}

J题 bfs
每一步转的数字只能是连续的,转化为bfs的话一共就20个方向,只要存10个,然后分上下转就行了。
要注意的是,每次询问单独bfs会超时,需要预处理把所有状态跑一下,一共就0000~9999个状态,然后O(1)处理询问即可
赛时缺少了对状态数量的判断

#define _CRT_SECURE_NO_WARNINGS
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
#include <list>
#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <deque>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define scd(v) scanf("%d",&v)
#define scdd(a,b) scanf("%d %d",&a,&b)
#define endl "\n"
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define pb push_back
#define all(v) v.begin(),v.end()
#define mst(v,a) memset(v,a,sizeof(v))
#define ls p<<1
#define rs p<<1|1
//#define int long long
#define inf 0x7f7f7f7f
#define fi first
#define se second
#define pii pair<int , int >
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define AC return 0
const int N = 1e6 + 10;
const double eps = 1e-6;
char s1[10], s2[10];
int dir[][4] =
{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1},{1,1,0,0},{0,1,1,0},{0,0,1,1},{1,1,1,0},{0,1,1,1},{1,1,1,1}
};
struct ty
{int a, b, c, d;ty(int a, int b, int c, int d) :a(a), b(b), c(c), d(d) {}void print(){cout<<" de "<<endl;cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;}bool operator == (const ty&t){return (a==t.a)&&(b==t.b)&&(c==t.c)&&(d==t.d);}
};
int dis[12][15][15][15];
int v[11][11][11][11];
void bfs(ty s )
{dis[s.a][s.b][s.c][s.d] = 0;v[s.a][s.b][s.c][s.d] = 1;queue<ty> q; q.push(s);while ( !q.empty() ){ty t = q.front();q.pop();for (int i = 0; i < 10; i++){int a = (t.a + dir[i][0])%10;int b = (t.b + dir[i][1])%10;int c = (t.c + dir[i][2])%10;int d = (t.d + dir[i][3])%10;if ( !v[a][b][c][d] ){v[a][b][c][d]=1;dis[a][b][c][d] = dis[t.a][t.b][t.c][t.d] + 1;ty nt = { a,b,c,d };q.push(nt);}}for (int i = 0; i < 10; i++){int a = (t.a - dir[i][0]+10) % 10;int b = (t.b - dir[i][1]+10) % 10;int c = (t.c - dir[i][2]+10) % 10;int d = (t.d - dir[i][3]+10) % 10;if ( !v[a][b][c][d] ){v[a][b][c][d]=1;dis[a][b][c][d] = dis[t.a][t.b][t.c][t.d] + 1;ty nt = { a,b,c,d };q.push(nt);}}}
}
signed main()
{//  freopen("data.txt", "r", stdin);IOS;bfs({0,0,0,0});int T;cin>>T;while( T-- ){cin>>(s1+1)>>(s2+1);int a = (s1[1] - s2[1] + 10 )%10;int b = (s1[2] - s2[2] + 10 )%10;int c = (s1[3] - s2[3] + 10 )%10;int d = (s1[4] - s2[4] + 10 )%10;cout<<dis[a][b][c][d]<<endl;}AC;
}

时隔半年继续补题(2022,7,7)

L题
题意:n个点的完全图,删掉一颗边数为2n-1树(只删边),求剩下的点进行匹配的方案数。
做法:容斥+树上背包
(说实话,真想不到容斥)
由于是完全图,删2n-1条边,整个图还是强联通的,uv若都不在树上,则uv间的边存在。
设F(i)表示至少匹配i条树边的方案数
容斥的思路是 ans=∑i=0n(−1)iF(i)ans = \sum_{i=0}^n(-1)^iF(i)ans=∑i=0n​(−1)iF(i),因为树上背包已经可以把具体哪些点选出来了,所以不用二项式反演。
设f(i)表示选i条树边的方案数,g(i)表示除了所选树边的上的点外选其他i个点的方案数
就可以把“至少”分解为树上确定的边数+其他任意的边数(这容斥特别nb)
ans=∑i=0n(−1)if(i)∗g(2n−2i)ans = \sum_{i=0}^{n}(-1)^if(i)*g(2n-2i)ans=∑i=0n​(−1)if(i)∗g(2n−2i)

g(i)很好求(保证i为偶数),利用上面任意两点间的边都存在性质

则有g(i)=C(i,i/2)∗(i/2)!2n−ig(i) = \frac{C(i,i/2)*(i/2)!}{2^{n-i}}g(i)=2n−iC(i,i/2)∗(i/2)!​

f(i)利用树上背包求,设dp[u][i][0/1]表示结点u的子树中选i条边,当前结点u是否参与匹配
转移情况有三种:
原本u就不匹配,加入v后u还是不参与匹配(v是否匹配无影响)
1 dp[u][i+j][0]+=dp[u][i][0]∗(dp[v][j][0]+dp[v][j][1])dp[u][i+j][0] += dp[u][i][0] *( dp[v][j][0] +dp[v][j][1])dp[u][i+j][0]+=dp[u][i][0]∗(dp[v][j][0]+dp[v][j][1])

原本u就匹配(v是否匹配无影响)
2 dp[u][i+j][1]+=dp[u][i][1]∗(dp[v][j][0]+dp[v][j][1])dp[u][i+j][1] += dp[u][i][1] *( dp[v][j][0] +dp[v][j][1])dp[u][i+j][1]+=dp[u][i][1]∗(dp[v][j][0]+dp[v][j][1])

原本u不匹配,加入v后,u与v匹配
3 $dp[u][i+j+1][1] += dp[u][i][0] * dp[v][j][0] $

转移的时候需要另开个过渡数组,避免重复计数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pii pair<int ,int >
#define pb(v) push_back(v)
#define all(v) v.begin(),v.end()
#define int long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define endl "\n"
#define fi first
#define se second
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define AC return 0
#define ldb long double
const int N=4e3+5;
const int mod=998244353;
const double eps=1e-8;
int n,m;
std::vector<int> G[N];
int siz[N];
int f[N][N][2],g[N][2];
// 0不参与匹配
void dfs(int x,int fa){siz[x] = f[x][0][0] = 1;for(int y:G[x]){if( y == fa ) continue;dfs(y,x); mst(g,0);_for(i,0,siz[x]/2){_for(j,0,siz[y]/2){g[i+j][0] = (g[i+j][0] + f[x][i][0] *(f[y][j][0] + f[y][j][1]))%mod;g[i+j][1] = (g[i+j][1] + f[x][i][1] *(f[y][j][0] + f[y][j][1]))%mod;g[i+j+1][1] = (g[i+j+1][1] + f[x][i][0] * f[y][j][0]) %mod;}}siz[x]+=siz[y];for(int i=0;i<=siz[x]/2;i++)       //将过渡数组转移回dp数组f[x][i][0]=g[i][0],f[x][i][1]=g[i][1];}
}
ll qsm(int a,int b){ll ans=1,temp=a;while( b ){if( b&1 ) ans = (ans * temp)%mod;temp = ( temp * temp)%mod;b>>=1;}return ans;
}
int fac[N],ni_f[N];
ll C(int n,int m){if( m==n || m==0 ) return 1;if( n < m ) return 0;return fac[n] * ni_f[n-m]%mod * ni_f[m]%mod;
}
void ini(){fac[0]=1;int maxn = 4000;_for(i,1,maxn) fac[i] =  (fac[i-1] * i)%mod;ni_f[maxn] = qsm(fac[maxn],mod-2);_rep(i,maxn-1,0) ni_f[i] = ni_f[i+1] * (i+1)%mod;
}
signed main(){#ifndef ONLINE_JUDGEfreopen("in.txt", "r", stdin);
#endif  IOS;ini();cin>>n;_for(i,1,2*n-1){int u,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}dfs(1,0);int ans=0;_for(i,0,n){int flag = i&1?-1:1;int  t = qsm(2,n-i);ans = (ans + mod+flag * (f[1][i][0]+f[1][i][1]) %mod * C(2*n-2*i,n-i)%mod*fac[n-i]%mod* qsm(t,mod-2)%mod )%mod;}cout<<ans<<endl;AC;
}

M題
题意:给一个无向图G,有新图L(G),L(G)中的点为G中的边,新图中uv相连当且仅当G中的两边相邻,新的边权为原来两边的边权和。求L(G)中最大的独立边集权值和。
做法:第一个难点是转化题意。
观察发现,选L(G)的一条边,等价于G中取相邻的两边。易知,当边数为偶数时,答案是所有边权和。

当边数为奇数时候,不难想到删掉一条最小的边,使图变为偶图。但是当删掉的边是连接两个奇图的桥时,这样会有问题。因为两个奇图t1,t2需要递归地去删最小边min_t1,min_t2值到不没有 "奇-桥-奇"的情况,那不如直接删min(min_t1,min_t2)。
所以"奇-桥-奇"的情况跳过。
这种思路主要是实现起来有点困难。网上还看到并查集做法,不过没看懂。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pii pair<int ,int >
#define pb(v) push_back(v)
#define all(v) v.begin(),v.end()
#define int long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define endl "\n"
#define fi first
#define se second
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define AC return 0
#define ldb long double
const int N=3e5+5;
const int mod=1e9+7;
const double eps=1e-8;
int n,m,mi = inf;
int low[N],dfn[N],ti;
struct  ty{int t,next,w;bool bridge=0;
}edge[N<<1];
int head[N],tot=1;//若需要用反边的话,tot从1开始
void add(int x, int y ,int z){edge[++tot] = ty{y,head[x],z};head[x] = tot;
}
std::vector<ty> B;
int du[N];
void tarjan(int x ,int fa){low[x]=dfn[x]=++ti;for(int i=head[x] ;i;i=edge[i].next){int y = edge[i].t;int w = edge[i].w;if( !dfn[y] ){tarjan(y,x);low[x] = min(low[x],low[y]);if( low[y] > dfn[x]){// find bridgeedge[i].bridge = 1;edge[i^1].bridge = 1;B.push_back(ty{x,y,w});du[x]--,du[y]--;}}else if( dfn[y] < dfn[x] && y!=fa ){low[x] = min(low[x],dfn[y]);}}
}
int vis[N],col[N],temp[N],id,cnt;
void dfs1(int x,int fa){vis[x]=1;cnt += du[x]; // cnt degrees, to calculate the num of edgescol[x] = id;for(int i=head[x];i;i=edge[i].next){int y = edge[i].t;if( y==fa || vis[y] || edge[i].bridge ) continue;dfs1(y,x);}
}
vector<pii> G[N];
int siz[N];
void dfs2(int x,int fa){siz[x] = temp[x];//边数for(auto [y,w]:G[x]){if( y==fa ) continue;dfs2(y,x);if( siz[y]%2==0 ){//下面是偶数,这个桥可删mi = min(mi,w);}siz[x] += siz[y];siz[x]++;//加上桥}
}
signed main(){#ifndef ONLINE_JUDGEfreopen("in.txt", "r", stdin);
#endif  IOS;cin>>n>>m;int sum=0;_for(i,1,m){int u,v,w;cin>>u>>v>>w;add(u,v,w);add(v,u,w);du[u]++,du[v]++;//degree , use it behind sum += w;}   // tarjan(1,0);if( m%2==0 ){return cout<<sum<<endl,0;}tarjan(1,0);// find bridge// tarjan the points which is on both sides of the bridges_for(i,1,n){if( !vis[i] ){cnt = 0;id++;dfs1(i,0);temp[id] = cnt/2;}}// 缩点后重构图,是一颗树for(auto [u,v,w,bridge] :B){u = col[u];v = col[v];G[u].push_back({v,w});G[v].push_back({u,w});}dfs2(1,0);_for(i,2,tot){if( !edge[i].bridge ) mi = min(mi,edge[i].w);}cout<<sum-mi<<endl;AC;
}

21年icpc沈阳站记录相关推荐

  1. 2021 ICPC 沈阳站 D题 Journey to Un‘Goro (打表+找规律)

    2021 ICPC 沈阳站 D.Journey to Un'Goro [链接][http://codeforces.com/gym/103202/problem/D](http://codeforce ...

  2. 2018 ICPC 沈阳站

    细胞色素训练3 排名:100/193 2018年ICPC沈阳站,学长在这里拿金了.听学长说开始时候很快的出了两题,排名第四,是可以进final的,然后一直没过题,直到最后封榜时候连过两题,金牌最后一名 ...

  3. 训练实录 | 第 45 届ICPC沈阳站(牛客重现赛)

    第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(沈阳)(重现赛) 传送门:ICPC沈阳 F - The Witchwood 这重现赛,这数据,我既然被hack了,我写的代码太拉跨了????? ...

  4. 2020 ICPC沈阳站-D,H

    icpc好难啊,希望有生之年能拿牌ort..... D. Journey to Un'Goro (思维) 链接:https://codeforces.com/gym/103202/problem/D ...

  5. 走迷宫爆压,21行突破B站记录(自创,自设地图)

    Cgame 大家都知道 但总是无趣,甚至玩个游戏都得打50行以上 这对初学者不太友好 但我想到了压缩 压缩一个走迷宫移动的的代码 压缩前 ch=getch();if(ch=='d'){if(a[y][ ...

  6. 22年ICPC西安站记录

    \quad 最后rank119铜. \quad 经过桂林被挨打经历后,西安站赛前佛系了许多,完全没有压力,桂林赛前辗转难眠,昨晚打完游戏后就睡着了2333.十点起床做完核酸后就冲去院楼了. \quad ...

  7. 2018 ACM/ICPC 沈阳站小结

    第二次现场赛,能拿金已经很开心了 热身赛 开幕式后的热身赛都是训练过的三个题,40min基本就解决了,剩下的时间就是在调试机器什么的 现场赛 上来队友先过了J的模拟,我看了看G题,发现可做就直接上了, ...

  8. 第45届ICPC沈阳站部分题解(D、F、G、H、I、J、K)

    文章目录 D-前缀和思想+dfs F-贪心 G H-双指针+dp 题意 思路 代码 I-追及问题+裴蜀定理 J-可持久化线段树 K-前缀和+积分的定义 题意 思路 参考链接 传送门 本文CSDN 本文 ...

  9. 2018 ACM/ICPC 沈阳站 J How Much Memory Your Code Is Using?

    题目描述 In the C++ language, the values of variables are stored somewhere in the computer memory as zer ...

最新文章

  1. Python 计算欧氏距离
  2. 原创不易!做网络推广怎么才能更好地保护网站的原创文章?
  3. 控制寄存器和系统地址寄存器
  4. IT人的十八般武艺-序言
  5. 外部开发:部件属性 外部exe启动UG NX
  6. 发布订阅之topics
  7. var result = ![] == []; console.log(result); // 结果是?为什么?
  8. 【转】wpa_supplicant与wpa_cli之间通信过程
  9. JAVA 8:Lambdas表达式初体验
  10. qt制作串口调试工具
  11. 测试环境服务器windows server 2003资源下载
  12. GitHub官网入门教程翻译
  13. 天之痕java 郡王府_轩辕剑3外传天之痕图文攻略【含支线任务】
  14. 美国国债收益率回复2021年年初水平 黄金同时趋向上走势
  15. 【Matlab】【碎碎念】 clc、close、close all、clear、clear all等的含义
  16. 民生银行java面试_民生银行面试题目 是什么?
  17. 女性最容易出轨的8种职业
  18. PNG透明图片叠加(Opencv实现,包括旋转缩放以及边界处理)
  19. 北理工计算机系裴教授,裴 炤
  20. java cmd进入目录_cmd进入某个目录

热门文章

  1. 蓝牙相关学习:4.2.BLE空口包结构 - PDU
  2. 路由器设置服务器用什么协议,路由器配置基础知识
  3. 计算机组成原理oe表示什么意思,计算机组成原理课后习题答案解析
  4. 南京那边可以学计算机绘画,电脑画画软件有哪些?推荐几款可以教画画的app
  5. 高德地图-添加一个或多个覆盖物
  6. !!!Adb 抓不住Genymotion的解决方法
  7. 【报告分享】2022年轻人未来恋爱白皮书-36氪后浪研究所(附下载)
  8. 基于matlab的低秩结构重构算法仿真实现,对比ALM,IT,APG,ADMM
  9. 面向NLP的AI产品方法论——如何设计多轮语音技能
  10. 04 面向对象之:三大特性:继承,封装,多态