2022 ICPC Gran Premio de Mexico 1ra Fecha (BDEF)
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022 ICPC Gran Premio de Mexico 1ra Fecha (BDEF)相关的知识,希望对你有一定的参考价值。
小技巧:
stoi(str,0,2) 将从0开始的二进制串转化为十进制串
不是标准函数,慎用(一般应该没问题吧……)
本次补的题应该都是铜、银牌题,可能欧洲场简单很多
D. Different Pass a Ports
好久没做快速幂的题目了,换了个题目背景,差点没看出来。
分析:
1.只要存在双向线路,便可去往别的港口,但不能停着不动。
2.港口间可重复访问。线路便可看作对矩阵的初始化。从港口1开始,需要初始化一个值为1的矩阵,每次对线路进行选择,即乘上初始化的矩阵。
分析下来,可简化为矩阵1*线路矩阵^k^
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
//const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b)
int res=1;
while(b)
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
return res;
int getinv(int x)return qpow(x,mod-2);
int C(int a,int b)
return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
int n,m,k;
struct Matrix
static const int N=102; //开设的矩阵
int a[N][N];
Matrix(int e=0) //矩阵清0
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]=e*(i==j);
Matrix mul(Matrix A,Matrix B) //矩阵的乘法运算 A*B
Matrix ans(0); //初始化全为0的矩阵
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
//模拟乘法运算
ans.a[i][j]=(ans.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
return ans; //返回
Matrix ksm(Matrix A,int b)
Matrix ans(1); //初始化为1的矩阵
while (b)
if (b&1)ans=mul(ans,A); //快速幂
A=mul(A,A);
b>>=1;
return ans;
;
Matrix A;
void solve()
cin>>n>>m>>k;
for(int i=1;i<=m;i++)
int u,v;cin>>u>>v;
A.a[u][v]=1;A.a[v][u]=1;
Matrix B=A.ksm(A,k);
int ans=0;
for(int i=1;i<=n;i++)
ans=(ans+B.a[1][i])%mod;
cout<<ans<<endl;
signed main()
ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
B. Building 5G antennas
思路:
1.f[v][dis]表示点v,对于当天的距离为j,最早可到达的天数。
2.使用set容器记录前一天可连接点的最小值,此处利用了set的自动排序功能。
3.每次将当天可到达的点记录下,压入到队列中,在都放入集合中。
#include<bits/stdc++.h>
//#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=1e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b)
int res=1;
while(b)
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
return res;
int getinv(int x)return qpow(x,mod-2);
int C(int a,int b)
return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
int n,k,f[N][105];
struct node
int x,dis,fa;
;
bool vis[N];
vector<int>e[N],ans;
set<int>st;queue<node>q;
void solve()
cin>>n>>k;
for(int i=1;i<n;i++)
int u,v;cin>>u>>v;
e[u].push_back(v),e[v].push_back(u);
for(int i=1;i<=n;i++) for(int j=0;j<105;j++) f[i][j]=inf;
vis[1]=1;
st.insert(1); //set容器默认将小值放前面
for(int i=0;i<n;i++) //每天建造的网线
if(!st.size()) break;
int x=*st.begin();
st.erase(st.begin());
q.push(x,0,0);
f[x][0]=i+1;
ans.push_back(x);
while(!q.empty())
auto tmp=q.front();
int u=tmp.x,dis=tmp.dis;
q.pop();
if(!vis[u])
vis[u]=1;st.insert(u);
if(dis<k)
for(int v:e[u])
if(v==tmp.fa) continue;
if(f[v][dis+1]>f[u][dis])
f[v][dis+1]=f[u][dis];
q.push(v,dis+1,u);
for(int x:ans) cout<<x<<" ";
cout<<endl;
signed main()
ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
E. Erudite of words
思路:
1.本题为数学推公式的题目。在M个字母中选取K个字母构成长度为N的字符串的方案数。
2.首先能想到从M个字母中选取k个字母为方案数为C(m,k)
3.长度为n,将k个字母随机放到n个位置。求出由k个字母构成的总方案数减去由c个字母构成的字符串(c<k)
4.f[i]表示由i个字母构成的长度为n的字符串。f[i]=i^n^-(1~j)*C(i,j)*f[j]的累加和
5.最后再乘上C(m,k)
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=1e6+5;
const int inf=1e18;
const int mod=1e9+7;
int n,m,k,fac[N],f[5005],inv[N];
int qpow(int a,int b)
int res=1;
while(b)
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
return res;
int getinv(int x)return qpow(x,mod-2);
int C(int a,int b)
return (fac[a]*inv[a-b]%mod)*inv[b]%mod;
void init()
fac[0]=1;
for(int i=1;i<=N;i++) fac[i]=fac[i-1]*i%mod;
/* 线性求逆元 受数据范围限制
inv[1]=1;
for(int i=2;i<n;i++)
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
*/
inv[N]=getinv(fac[N]);
for(int i=N-1;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod;
void solve()
init();
cin>>n>>m>>k;
for(int i=1;i<=k;i++)
f[i]=qpow(i,n)%mod;
for(int j=1;j<i;j++)
f[i]=(f[i]-C(i,j)*f[j]%mod+mod)%mod;
cout<<f[k]*C(m,k)%mod<<endl;
signed main()
ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
矩阵快速幂使用情况:
1.数据规模很大
2.有递推公式
F. Froginald the frog
需要再打一个表,能省很多时间。不然每一段都要进行一次快速幂,会tle。看的一篇题解也tle了,数据更新了,需要打表优化下。明天试试
思路:
1.被多个点分成了多个区间,答案为各个区间得累乘。
2.当两个点值差值为1时,到不了终点;为2、3时,只有一种情况;差值为4时有2种情况,符合斐波那契,eg:4、8,可行区间为【5,7】
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=1e6+5;
const int inf=1e18;
const int mod=1e9+7;
int n,m,a[N];
struct Matrix
static const int N=3; //开设的矩阵
int a[N][N];
int n=2;
Matrix(int e=0) //矩阵清0
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]=e*(i==j);
Matrix mul(Matrix A,Matrix B) //矩阵的乘法运算 A*B
Matrix ans(0); //初始化全为0的矩阵
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
//模拟乘法运算
ans.a[i][j]=(ans.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
return ans; //返回
Matrix ksm(Matrix A,int b)
Matrix ans(1); //初始化为1的矩阵
while (b)
if (b&1)ans=mul(ans,A); //快速幂
A=mul(A,A);
b>>=1;
return ans;
以上是关于2022 ICPC Gran Premio de Mexico 1ra Fecha (BDEF)的主要内容,如果未能解决你的问题,请参考以下文章
2019 ICPC Universidad Nacional de Colombia Programming Contest
2020 ICPC Universidad Nacional de Colombia Programming Contest---D
2017 ACM-ICPC, Universidad Nacional de Colombia Programming Contest K - Random Numbers (dfs序 线段树+数论)
2020 ICPC Universidad Nacional de Colombia Programming Contest---A