早上想寫一些相關的證明,發現自己出了結合律和一些感性認識外,講不出理性的證明。。。
所以只能先給出例題,大家感性的理解一下。。
思路:看完題(解 )之後,可以得到一個推論:放完i個括號之後,最多不會超過2n個左括號未匹配。
那麼,先預處理出從i個未匹配的左括號放n個括號之後轉移到j個未匹配的左括號需要的 最小花費,然後直接做冪次爲m的矩陣快速冪即可。
#include <bits/stdc++.h>
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;
}
思路:從當前六邊形到下一個六邊形顯然只能通過1,2號節點,那麼總共就有2個位置,每個位置2個方向,共四種狀態。那麼先手推出四種狀態互相轉移的最小花費。然後剩下的就跟上面的題一樣了。還有一些別的細節自己需要注意一下即可。
#include <bits/stdc++.h>
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;
}