早上想写一些相关的证明,发现自己出了结合律和一些感性认识外,讲不出理性的证明。。。
所以只能先给出例题,大家感性的理解一下。。
cf352E
思路:看完题(解 )之后,可以得到一个推论:放完i个括号之后,最多不会超过2n个左括号未匹配。
那么,先预处理出从i个未匹配的左括号放n个括号之后转移到j个未匹配的左括号需要的 最小花费,然后直接做幂次为m的矩阵快速幂即可。
#include
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
int n,m,a[N],b[N];
int dp[22][44];
struct uzi{
LL A[44][44];
uzi(){
memset(A,0x3f3f3f,sizeof A);
};
}G;
uzi operator * (const uzi & a,const uzi & b){
uzi c;
for(int i=0;i<=40;i++){
for(int j=0;j<=40;j++){
for(int k=0;k<=40;k++){
c.A[i][j]=min(a.A[i][k]+b.A[k][j],c.A[i][j]);
}
}
}
return c;
}
uzi pm(){
uzi c;
for(int i=0;i<=40;i++)c.A[i][i]=0;
while(m){
if(m&1)c=c*G;
G=G*G;
m>>=1;
}
return c;
}
int main() {
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
cin>>b[i];
}
for(int i=0;i<=40;i++){
for(int j=0;j<=n;j++){
for(int k=0;k<=40;k++){
dp[j][k]=1e9;
if(!j){
if(k==i)dp[j][k]=0;
}else{
if(k){
dp[j][k]=min(dp[j][k],dp[j-1][k-1]+a[j-1]);
}
if(k+1<=40){
dp[j][k]=min(dp[j][k],dp[j-1][k+1]+b[j-1]);
}
}
}
for(int k=0;k<=40;k++){//计算左括号的转移量 从i转移到k最小花费
G.A[i][k]=dp[n][k];
}
}
}
cout<<pm().A[0][0];
return 0;
}
Namomo Test Round 1 C.polygon
思路:从当前六边形到下一个六边形显然只能通过1,2号节点,那么总共就有2个位置,每个位置2个方向,共四种状态。那么先手推出四种状态互相转移的最小花费。然后剩下的就跟上面的题一样了。还有一些别的细节自己需要注意一下即可。
#include
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
int t;
LL x,y,k,l;
int dx[6][4]={//起点到4个状态
{0,0,1,1},
{1,1,0,0},
{1,1,0,1},
{0,1,1,1},
{1,1,1,0},
{1,0,1,1}
};
int dy[4][6]={//重点到4个状态
{1,1,1,1,0,0},
{1,0,1,1,0,1},
{0,1,1,0,1,1},
{1,1,0,0,1,1}
};
int A[4][4]={
{2,1,2,1},
{1,2,1,0},
{0,1,2,1},
{1,2,1,2}
};
struct uzi{
LL a[4][4];
uzi(){
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
a[i][j]=1e18;
}
}
}
};
uzi operator * (const uzi a,const uzi b){
uzi c;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
for(int k=0;k<4;k++){
c.a[i][j]=min(c.a[i][j],a.a[k][j]+b.a[i][k]);
}
}
}
return c;
}
uzi pm(LL pw){
uzi ans,res;
for(int i=0;i<4;i++)ans.a[i][i]=0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
res.a[i][j]=A[i][j];
}
}
while(pw){
if(pw&1)ans=ans*res;
res=res*res;
pw>>=1;
}
return ans;
}
int main() {
ios::sync_with_stdio(false);
for(cin>>t;t;t--){
cin>>x>>y>>k>>l;
if(x>k){
swap(x,k);
swap(y,l);
}
if(x==k){
int z=(y-l+6)%6;
if(z==2||z==4)cout<<1<<'\n';
else cout<<0<<'\n';
}else{
uzi ge=pm(k-x-1);
LL ans=1e18;
if(k-x-1==0){
if((y==2||y==1) && (l==5||l==4)){
cout<<0<<'\n';
continue;
}
for(int i=0;i<4;i++){
ans=min(ans,0ll+dx[y-1][i]+dy[i][l-1]);
}
cout<<ans<<'\n';
continue;
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
ans=min(ans,dx[y-1][i]+ge.a[i][j]+dy[j][l-1]);
}
}
cout<<ans<<'\n';
}
}
return 0;
}