Noip yjm 题解
Noip yjm 题解
T1 分治
因为题目描述分为前半段和后半段,且长度满足\(n=2^k\),所以不难想到分治。
然后分别判断是否满足三个条件之一,分别统计如果把当前串前半段变为全是ch,或后半段全变为ch所需代价,递归到下一层进行统计
int sol(int ch,int l,int r)
{
if(l+1==r) return s[l]!=ch;//满足条件1,只有一个字母ch
int mid=(l+r)>>1,cl=0,cr=0;
per(i,l,mid-1) cl+=(s[i]!=ch);//统计将前半段变成全是ch的代价
per(i,mid,r-1) cr+=(s[i]!=ch);//统计将后半段变成全是ch的代价
return min(cl+sol(ch+1,mid,r),cr+sol(ch+1,l,mid));//分治求解
}
代码
#include <bits/stdc++.h>
using namespace std;
#define per(i,a,b) for(int i(a);i<=b;++i)
const int N=131080;
char s[N];
int sol(int ch,int l,int r)
{
if(l+1==r) return s[l]!=ch;
int mid=(l+r)>>1,cl=0,cr=0;
per(i,l,mid-1) cl+=(s[i]!=ch);
per(i,mid,r-1) cr+=(s[i]!=ch);
return min(cl+sol(ch+1,mid,r),cr+sol(ch+1,l,mid));
}
int main ()
{
int t,n;
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>n>>s+1;
cout<<sol('a',1,n+1)<<'\n';
}
return 0;
}
T2 思维+图的遍历
如果一支军队在相同天气下能打赢另一只军队,则从战败方向战胜方引一条有向边。
从某一个地图中的战力值最大的点开始遍历,能遍历到的都是符合题意的
(战力值最大的一定能赢得所有的点,他能到达的点为能(直接或间接)战胜它的点)所以被遍历到的点都能获得总冠军
代码
#include <bits/stdc++.h>
using namespace std;
#define per(i,a,b) for(int i(a);i<=b;++i)
const int N=1e5+10;
struct aaa{
int x,y,id;
}a[N];
vector<int>mp[N];
bitset<N>ck;
void addd(int x,int y) { mp[x].push_back(y);}
bool cmp1(aaa f,aaa s) { return f.x<s.x;}
bool cmp2(aaa f,aaa s) { return f.y<s.y;}
void sol(int x)
{
if(ck[x]) return;
ck[x]=1;
per(i,0,(int)mp[x].size()-1) sol(mp[x][i]);
}
int main ()
{
int n,t,rt;
cin>>t;
while(t--)
{
cin>>n;
per(i,1,n) scanf("%d",&a[i].x);
per(i,1,n) scanf("%d",&a[i].y),a[i].id=i,mp[i].clear();
sort(a+1,a+n+1,cmp1);
per(i,1,n-1) addd(a[i].id,a[i+1].id);
rt=a[n].id;
sort(a+1,a+n+1,cmp2);
per(i,1,n-1) addd(a[i].id,a[i+1].id);
ck.reset();
sol(a[n].id);
sol(rt);
per(i,1,n)
{
if(ck[i]) printf("1");
else printf("0");
}
puts("");
}
return 0;
}
T3 矩阵快速幂
30tps:暴力算法,O(n) \(dp[i][j]\)表示当前用了\(i\)个篮球,占了\(j\)个位置的方案数
优化减去一个维度变成一维\(dp[i]\)表示占用i个位置的方案数,如果上一个操作加入的是一个魔法篮球,\(dp[i]+=dp[i-1]\);如果上一个操作加入的是由一个魔法篮球分解得到的普通篮球,\(dp[i]+=dp[i-m]\),所以转移方程为\(dp[i]=dp[i-1]+dp[i-m]\)。
考虑优化,引入矩阵快速幂
状态矩阵A={\(dp[0],dp[1],...,dp[m-1]\)}
构造转移矩阵B,使{\(dp[0],dp[1],...,dp[m-1]\)}*B={\(dp[1],dp[2],...,dp[m]\)}
所以A*Bn的\(dp[n]\)即为答案,即\(A[1][1]\)
构建的矩阵B的主要目的是将A每位都向前移动,所以\(B[i+1][i]=1,B[1][m]=1,B[m][m]=1\)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
#define ll long long int
struct matrix{
ll x[200][200];
};
ll n,m;
matrix mul(const matrix &a, const matrix &b)
{
matrix ans;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
ans.x[i][j]=0;
for(int k=1;k<=m;k++)
{
ans.x[i][j] += a.x[i][k] * b.x[k][j];
ans.x[i][j] %= mod;
}
}
}
return ans;
}
matrix qpow(matrix a,ll b)
{
matrix ans;
for(int i=1;i<=m;i++)ans.x[i][i]=1;
while(b)
{
if(b&1)ans = mul(ans, a);
a = mul(a, a);
b>>=1;
}
return ans;
}
int main()
{
cin>>n>>m;
if(n<m){cout<<1<<endl;return 0;}
matrix base;
for(int i=1;i<m;i++) base.x[i+1][i] = 1;
base.x[1][m] = base.x[m][m] = 1;
base = qpow(base, n-m);
matrix ans;
for(int i=1;i<m;i++)ans.x[1][i]=1;
ans.x[1][m] = 2;
ans = mul(ans, base);
cout<<ans.x[1][m]<<endl;
return 0;
}
T4 期望概率dp
设 \(h[i][j]\) 表示 \(n=i,k=j\) 的结果
每个质因子的贡献实际上是独立的,反应在次数上就是相乘的关系
因此,每个质因子分别贡献,总答案为乘积
现在对于每个质因子分别算即可
对于 p,设 \(f[i][j]\)表示 \(n=p^i,k=j\) 的结果,那么 \(f[i][j]={1\over i+1}\sum_{k=0}^j f[k][j−1]\)
https://www.cnblogs.com/bcoier/p/11621145.html
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int f[60][10005];
int qpow(int p, int q)
{
return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
}
int solve(int p, int i, int j)
{
if (f[i][j])
return f[i][j];
if (i == 0)
return f[i][j] = 1;
if (j == 0)
return f[i][j] = qpow(p, i);
f[i][j] = 0;
for (int k = 0; k <= i; k++)
f[i][j] += solve(p, k, j - 1);
return f[i][j] = f[i][j] % mod * qpow(i + 1, mod - 2) % mod;
}
signed main()
{
ios::sync_with_stdio(false);
int n, k;
cin >> n >> k;
int ans = 1;
for (int i = 2; i * i <= n; i++)
if (n % i == 0)
{
int cnt = 0;
while (n % i == 0)
n /= i, ++cnt;
memset(f, 0, sizeof f);
ans *= solve(i, cnt, k);
ans %= mod;
}
memset(f, 0, sizeof f);
if (n > 1)
ans *= solve(n, 1, k);
ans %= mod;
cout << ans << endl;
}