前言
-
\(T1~100pts\) :最開始沒想出來,打了 \(T3\) 才去打。
-
\(T2~0pts\) :程式碼太難調沒打出來。
-
\(T3~0pts\) :記憶化打假了,而且 \(ans\) 初始值忘記為 \(0\) ,且捆綁測試……
-
\(T4~0pts\) :無人會。
-
比賽連結 。
T1 特殊字串
用 \(f_i\) 表示前 \(i\) 個字元中並以第 \(i\) 個字元結尾的最大奇異值。
因為每個 \(p_i\) 長度為 \(2\) ,不妨列舉另一個字元進行轉移,有:
其中 \(last_j\) 表示字元 \(j\) 上次出現的位置,\(t\) 表示組成的長度為 \(2\) 的字串會產生多少貢獻,至於每個字串產生多少貢獻可以在輸入時直接預處理出來。
點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e6+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,m,last[N],ans,f[N];
char s[N],t[N];
map<string,int>a;
signed main()
{
// #ifndef ONLINE_JUDGE
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
// #endif
freopen("shiki.in","r",stdin);
freopen("shiki.out","w",stdout);
read(n);
cin>>s+1;
read(m);
for(int i=1,k;i<=m;i++)
cin>>t[1]>>t[2],
read(k),
a[string(t+1)]+=k;
last[s[1]-'a']=1;
for(int i=2;i<=n;i++)
{
t[2]=s[i];
for(int j=0;j<26;j++)
{
if(!last[j]) continue;
t[1]=j+'a';
f[i]=max(f[i],f[last[j]]+a[string(t+1)]);
}
last[s[i]-'a']=i;
ans=max(f[i],ans);
}
write(ans);
}
T2 寶可夢
保證路徑唯一,說明其可以構成一棵樹的結構,從一個點出發一定能遍歷整個圖,所以對其進行預處理。
右面沒牆就右轉,否則能直行就直行,再不行就就左轉。
所以對於任意一個.
,對他預處理即可,其最後會形成一個環,此時結束即可,但是他重複走到自己不一定是真正的環,還需要求方向一致。
由於其為一棵樹,查詢時直接可以算出路徑。
就是程式碼不太好調。
點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=5e5+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,m,q,f[N<<1][4][2],sum[4];
char a[N<<1];
int gox[4]={-1,1,0,0},goy[4]={0,0,-1,1};//上下左右,直行。
int r[4]={3,2,0,1},l[4]={2,3,1,0};
int id(int x,int y) {return x*(m+2)+y;}
void work(int x,int y,int p)
{
int d=p,tx=x,ty=y;
f[id(x,y)][d][p]=min(sum[p],f[id(x,y)][d][p]);
int xx=x+gox[d],yy=y+goy[d];
if(a[id(xx,yy)]=='.') x=xx,y=yy,sum[p]++;
else d=l[d];
if(a[id(x+gox[r[d]],y+goy[r[d]])]=='.') d=r[d];
while(x!=tx||y!=ty||d!=p)
{
f[id(x,y)][d][p]=min(sum[p],f[id(x,y)][d][p]);
int xx=x+gox[d],yy=y+goy[d];
if(x==tx&&y==ty&&d==p) break;
if(a[id(xx,yy)]=='.') x=xx,y=yy,sum[p]++;
else for(int i=1;i<=3&&(x!=tx||y!=ty||d!=p);i++)
d=r[d];
if(x==tx&&y==ty&&d==p) break;
if(a[id(x+gox[r[d]],y+goy[r[d]])]=='.') d=r[d];
}
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
freopen("pokemon.in","r",stdin);
freopen("pokemon.out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m+1;j++)
if(j==0||j==m+1)
a[id(i,j)]='X';
else cin>>a[id(i,j)];
for(int i=0;i<=m+1;i++)
a[id(0,i)]=a[id(n+1,i)]='X';
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[id(i,j)]=='.')
{
work(i,j,1);
goto Charlie;
}
Charlie:;
read(q);
while(q--)
{
int x,y,xx,yy;
char op;
read(x),read(y),read(xx),read(yy);
cin>>op;
int d=op=='U'?0:(op=='D'?1:(op=='L'?2:3));
int inf=0x3f3f3f3f,ans=inf,p=1;
for(int i=0;i<4;i++)
if(f[id(x,y)][d][p]>=inf||f[id(xx,yy)][i][p]>=inf) continue;
else if(f[id(x,y)][d][p]<=f[id(xx,yy)][i][p])
ans=min(ans,f[id(xx,yy)][i][p]-f[id(x,y)][d][p]);
else ans=min(ans,sum[p]+(f[id(xx,yy)][i][p]-f[id(x,y)][d][p]));
write(ans),puts("");
}
}
T3 矩陣
前言
首先注意初始值為 \(1\) ,出資料的在每個捆綁裡都放了一個 \(1\) ,導致大量人員爆零。
其次,卡時常+暴力 \(dfs\) 可過,剪枝+暴力 \(dfs\) 喜提最優解。
只能說資料比較屎。
部分分
-
\(TLE~60pts\) :直接暴力 \(dfs\) ,若一次 \(dfs\) 的公比為 \(d\) ,那麼本次 \(dfs\) 的複雜度最多為 \(4^{log_d(maxx)}\) ,\(maxx\) 為其中最大值,\(log\) 以 \(d\) 為底,需要跑 \(nm\) 遍 \(dfs\) 。
-
卡時常,在時間達到 \(980ms\) 時直接結束執行,這能過屬實抽象。
點選檢視卡時常函式
inline bool check(){return (1.0*clock())/(1.0*CLOCKS_PER_SEC)<=0.98;}
正解
剪枝。
發現每次 \(dfs\) 的 \(ans\) 最大為 \(log_d(maxx)\) ,所以噹噹前 \(ans>log_d(maxx)\) 時就不進行此次 \(dfs\) ,於是喜提最優解。
貌似不算真正的正解,但我記憶化打假了,懶得調了。
點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=100010;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,m,a[N],ans,used[N][4],maxx;
int h[4]={1,0,-1,0},z[4]={0,1,0,-1};
// inline bool check(){return (1.0*clock())/(1.0*CLOCKS_PER_SEC)<=0.98;}
bool check(int i,int j)
{
if(i<1||i>n) return 0;
if(j<1||j>m) return 0;
return 1;
}
void dfs(int i,int j,int sum,int d)
{
ans=max(ans,sum);
for(int l=0;l<4;l++)
if(check(i+h[l],j+z[l]))
if(a[(i+h[l])*m+j+z[l]]%a[i*m+j]==0&&a[(i+h[l])*m+j+z[l]]/a[i*m+j]==d)
dfs(i+h[l],j+z[l],sum+1,d);
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
read(n),read(m);
ans=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
read(a[i*m+j]),
maxx=max(a[i*m+j],maxx);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
if(check(i+h[k],j+z[k]))
if(a[(i+h[k])*m+j+z[k]]==a[i*m+j])
puts("-1"),
exit(0);
else if(a[(i+h[k])*m+j+z[k]]%a[i*m+j]==0)
{
int d=a[(i+h[k])*m+j+z[k]]/a[i*m+j];
if(log(maxx)/log(d)<=ans) continue;
dfs(i+h[k],j+z[k],2,a[(i+h[k])*m+j+z[k]]/a[i*m+j]);
}
write(ans);
}
T4 乘法
不會。