使用vue-cli建立專案並webpack打包的操作方法
A - atcoder < S
列舉操作完的串 \(s\) 和 atcoder
相同的字首長度,算出前面的字首相同的代價加上當前這位大於 atcoder
中對應的那一位的代價即為達到當前狀態的代價,取個最小值即可。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1005; const int INF=1061109567; int T; int n; char s[N]; char t[]={" atcoder`"}; void solve() { scanf("%s",s+1); n=strlen(s+1); int ans=INF; int now=0; for(int i=1;i<=min(n,8);i++) { for(int j=i+1;j<=n;j++) if(s[j]>t[i]) { ans=min(ans,now+j-i); break; } if(s[i]<t[i]) { for(int j=i+1;j<=n;j++) if(s[j]==t[i]) { now+=j-i; for(int k=i;k<j;k++) s[k]=s[k+1]; s[j]=t[i]; break; } break; } else if(s[i]>t[i]) { ans=min(ans,now); break; } } if(ans>=INF) printf("-1\n"); else printf("%d\n",ans); return; } int main() { scanf("%d",&T); while(T--) solve(); return 0; }
B - Bracket Score
最後 ()
的位置一定為一半奇數一半偶數。先把所有 \(b_i\) 加入答案。把奇數位和偶數位的 \(a_i-b_i\) 從大到小排序,每次從奇數位和偶數位分別拿出一個,如果加入當前的兩個數會使答案變大就加入。
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; const int N=200005; int n; int a[N],b[N]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); vector<int>odd,even; for(int i=1;i<=n;i++) if(i&1) odd.emplace_back(a[i]-b[i]); else even.emplace_back(a[i]-b[i]); long long ans=0; for(int i=1;i<=n;i++) ans+=b[i]; sort(odd.begin(),odd.end(),greater<int>()); sort(even.begin(),even.end(),greater<int>()); for(int i=0;i<n/2;i++) if(odd[i]+even[i]>=0) ans+=odd[i]+even[i]; printf("%lld",ans); return 0; }
C - Penguin Skating
每次操作相當於是將差分陣列某個位置的值 \(-1\) 後加到相鄰的一個位置上,然後再將這個位置的值置為 \(1\),雙指標搞搞就好了。
#include<iostream> #include<cstdio> #include<cmath> using namespace std; const int N=100005; int n,L; int a[N],b[N]; int sa[N],sb[N]; int main() { scanf("%d%d",&n,&L); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); a[0]=0,b[0]=0; n++,a[n]=L+1,b[n]=L+1; for(int i=1;i<=n;i++) sa[i]=a[i]-a[i-1]-1,sb[i]=b[i]-b[i-1]-1; long long ans=0; for(int i=1,j=1;i<=n;i++) { long long sum=0; int l=n+1,r=0; while(j<=n&&sum+sa[j]<=sb[i]) { if(sa[j]) l=min(l,j),r=max(r,j); sum+=sa[j],j++; } if(l<=r) { if(i<l) ans+=r-i; else if(i>r) ans+=i-l; else ans+=r-l; } if(sum!=sb[i]) { printf("-1"); return 0; } } printf("%lld",ans); return 0; }
D - Pocky Game
可以發現,一堆石子要麼一個個取,要麼一次性取完。
令 \(f_{l,r,0/1,x}\) 表示 \([l,r]\) 這段區間,左邊/右邊是 \(x\) 時誰能勝利。
\(x\) 的範圍很大,考慮令 \(f_{l,r,0/1}\) 表示 \([l,r]\) 這段區間,第一個人/第二個人勝利 \(a_l\)/\(a_r\) 至少為多少。
考慮轉移 \(f_{l,r,0}\),\(f_{l,r,1}\) 同理。
- 當 \(f_{l+1,r,1}\gt a_r\) 時,\(f_{l,r,0}=1\),此時無論 \(a_l\) 取多少第一個人都必勝;
- 當 \(f_{l+1,r,1}\le a_r\) 時,此時兩個人肯定會輪流取一個,直到最右邊的那一堆被取到 \(f_{l+1,r,1}\) 時,第二個人肯定只能將最右邊那堆直接取完,否則第一個人直接將第一堆取完第二個人就輸了,換句話說,就是:\(f_{l,r,0}-f_{l,r-1,0}\gt a_r-f_{l+1,r,1}\Leftrightarrow f_{l,r,0}=f_{l,r-1,0}-f_{l+1,r,1}+a_r+1\)。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=105;
int T;
int n;
int a[N];
long long f[N][N][2];
long long dfs(int l,int r,int k)
{
if(l==r) return f[l][r][k]=1;
if(f[l][r][k]!=-1) return f[l][r][k];
if(k==0)
{
if(dfs(l+1,r,k^1)>a[r]) f[l][r][k]=1;
else f[l][r][k]=a[r]-dfs(l+1,r,k^1)+dfs(l,r-1,k)+1;
}
else
{
if(dfs(l,r-1,k^1)>a[l]) f[l][r][k]=1;
else f[l][r][k]=a[l]-dfs(l,r-1,k^1)+dfs(l+1,r,k)+1;
}
return f[l][r][k];
}
void solve()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
memset(f,-1,sizeof(f));
if(dfs(1,n,0)<=a[1]) printf("First\n");
else printf("Second\n");
return;
}
int main()
{
scanf("%d",&T);
while(T--)
solve();
return 0;
}
E - Strange Relation
我們從後往前插入每個數,對於 \(a_i\) 放到 \(a_{i+1},\cdots ,a_n\) 前面對 \(x_i\cdots x_n\) 的影響:
- \(x_i=0\)
- \(a_i \lt a_j+T\times (x_j+1)\),令 \(x_j=x_j+1\)(不加肯定字典序比加字典序小)。
- \(a_i \ge a_j+T\times (x_j+1)\),\(x_j\) 不變。
可以發現對於每個 \(j\) 是獨立的。
對於每個位置 \(p\) 的每一個取值分別 DP,設 \(f_{i,j}\) 表示考慮 \(1\sim i\) 的影響時 \(x_p=j\) 的方案數。
因為 \(i+1\sim n\) 可以隨便選,答案還要乘上 \(k^{n-p}\),貢獻即為 \(k^{n-p}\sum\limits_{i=0}^n i\cdot f_{1,i}\)。
#include<iostream>
#include<cstdio>
using namespace std;
const int N=55;
const int MOD=1000000007;
int n,m,t;
int b[N][N];
int f[N][N];
int main()
{
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&b[i][j]);
for(int i=1;i<=n;i++)
{
int ans=0;
for(int j=1;j<=m;j++)
{
f[i][0]=1;
for(int k=i;k>1;k--)
for(int l=0;l<n;l++)
for(int x=1;x<=m;x++)
if(b[i][j]+t*(l+1)>b[k-1][x]) f[k-1][l+1]=(f[k-1][l+1]+f[k][l])%MOD;
else f[k-1][l]=(f[k-1][l]+f[k][l])%MOD;
for(int k=1;k<n;k++)
ans=(ans+1LL*k*f[1][k])%MOD;
for(int k=1;k<=i;k++)
for(int l=0;l<=n;l++)
f[k][l]=0;
}
for(int j=i+1;j<=n;j++)
ans=1LL*ans*m%MOD;
printf("%d\n",ans);
}
return 0;
}
F - 01 Record
可以發現,對一個數連續操作一定是 \(01\) 交錯排列,結尾一定是 \(1\)。
考慮將整個序列翻轉後,相當於是每次刪去一個 \(101010\cdots\) 的子序列。
我們貪心的每次能刪儘量刪,令每次刪除的字串長度為 \(l_1,l_2,\cdots ,l_n\)。
令 \(S\) 中的元素從大到小分別為 \(x_1,x_2,\cdots ,x_m\),其中 \(m\ge n\),則一組 \(x\)合法當且僅當:
- \(L=\sum\limits_{i=1}^n l_i=\sum\limits_{i=1}^m x_i\)
- \(\forall 1\le i\le n,\sum\limits_{j=1}^i \lfloor \frac{l_j}{2}\rfloor\ge \sum\limits_{j=1}^i \lfloor \frac{x_j}{2}\rfloor\)
- \(\forall 1\le i\le n,\sum\limits_{j=1}^i \lceil \frac{l_j}{2} \rceil \ge \sum\limits_{j=1}^i \lceil \frac{x_j}{2} \rceil\)
具體證明可以看官方題解。
令 \(f_{i,j,k,t}\) 表示當前填到第 \(i\) 位,且 \(\sum\limits_{l=1}^i \lfloor \frac{x_l}{2}\rfloor=j\) 且 \(\sum\limits_{l=1}^i \lceil \frac{x_l}{2}\rceil=k\) 且 \(x_i=t\) 的方案數。因為 \(x_1\ge x_2\ge\cdots\ge x_i\),且 \(\sum\limits_{j=1}^i x_i\le L\),所以 \(t\le \lfloor \frac{L}{i}\rfloor\)。直接轉移即可。
答案即為:
\[\sum_{i=n}^L \sum_{t=1}^L f_{i,\sum\limits_{j=1}^n \lfloor \frac{l_j}{2}\rfloor,\sum\limits_{k=1}^n \lceil \frac{l_k}{2} \rceil,t} \]#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=305;
const int MOD=1000000007;
int n,m,L;
string s;
int a[N];
int s1[N],s2[N];
int f[2][N][N][N],g[2][N][N][N];
int main()
{
cin>>s;
L=s.size();
reverse(s.begin(),s.end());
while((int)s.size()>0)
{
if(s[0]!='1')
{
cout<<0;
return 0;
}
string t="";
int c=1;
n++;
for(int i=0;i<(int)s.size();i++)
if(s[i]-'0'==c) a[n]++,c^=1;
else t+=s[i];
s=t;
}
for(int i=1;i<=L;i++)
s1[i]=s1[i-1]+a[i]/2;
for(int i=1;i<=L;i++)
s2[i]=s2[i-1]+(a[i]+1)/2;
int cur=0;
f[0][0][0][L]=g[0][0][0][L]=1;
int ans=0;
for(int i=1;i<=L;i++)
{
cur^=1;
if(i-2>=0)
{
for(int j=0;j<=s1[i-2];j++)
for(int k=0;k<=s2[i-2];k++)
for(int t=0;t<=L/max(i-2,1);t++)
f[cur][j][k][t]=g[cur][j][k][t]=0;
}
for(int j=0;j<=s1[i];j++)
for(int k=0;k<=s2[i];k++)
{
for(int t=0;t<=L/i;t++)
if(j-t/2>=0&&k-(t+1)/2>=0) f[cur][j][k][t]=(g[cur^1][j-t/2][k-(t+1)/2][L/max(i-1,1)]-(t-1>=0?g[cur^1][j-t/2][k-(t+1)/2][t-1]:0))%MOD;
g[cur][j][k][0]=f[cur][j][k][0];
for(int t=1;t<=L/i;t++)
g[cur][j][k][t]=(g[cur][j][k][t-1]+f[cur][j][k][t])%MOD;
}
if(i>=n)
for(int t=1;t<=L/i;t++)
ans=(ans+f[cur][s1[n]][s2[n]][t])%MOD;
}
ans=(ans+MOD)%MOD;
printf("%d",ans);
return 0;
}