小技巧:
stoi(str,0,2) 将从0开始的二进制串转化为十进制串
不是标准函数,慎用(一般应该没问题吧……)
本次补的题应该都是铜、银牌题,可能欧洲场简单很多
D. Different Pass a Ports
好久没做快速幂的题目了,换了个题目背景,差点没看出来。
分析:
1.只要存在双向线路,便可去往别的港口,但不能停着不动。
2.港口间可重复访问。线路便可看作对矩阵的初始化。从港口1开始,需要初始化一个值为1的矩阵,每次对线路进行选择,即乘上初始化的矩阵。
分析下来,可简化为矩阵1*线路矩阵^k^
#include
#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
//#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个字母构成的字符串(cf[i]=i^n^-(1~j)*C(i,j)*f[j]的累加和
5.最后再乘上C(m,k)
#include
#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
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了,数据更新了,需要打表优化下。明天试试
优化后,多过了20多组样例,时间上没问题了,但runtime error了,不知道为啥。
思路:
1.被多个点分成了多个区间,答案为各个区间得累乘。
2.当两个点值差值为1时,到不了终点;为2、3时,只有一种情况;差值为4时有2种情况,符合斐波那契,eg:4、8,可行区间为【5,7】
#include
#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=2e6+5;
const int inf=1e18;
const int mod=1e9+7;
int n,m,a[N],ans[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;
}
};
void solve()
{
Matrix A;
A.a[1][1]=A.a[1][2]=A.a[2][1]=1;
cin>>n>>m;
for(int i=1;i<=m;i++) cin>>a[i];
Matrix B(1);
for(int i=1;i<=N;i++)
{
B=B.mul(B,A);
ans[i]=(B.a[1][1]+B.a[1][2])%mod;
}
sort(a+1,a+m+1);
a[0]=-1;
m++,a[m]=n+1;
int ss=1;
for(int i=1;i<=m;i++)
{
if(a[i]-a[i-1]==1)
{
cout<<0<<endl;return;
}
else if(a[i]-a[i-1]==2||a[i]-a[i-1]==3)
continue;
else
{
ss=ss*ans[a[i]-a[i-1]-3]%mod;
}
}
cout<<ss<<endl;
}
signed main()
{
ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
}