2022.7.14 AGC048D&AGC048E&AGC048F
AGC048D Pocky Game
题意:有 \(n\) 堆石子,每堆有 \(A_i\) 个。两个人玩游戏,先手每次从最左端拿取至少 \(1\) 个石子,后手从最右端拿。判断谁有必胜策略。
\(T\leqslant 100,n\leqslant 100,A_i\leqslant 10^9\)
瞎扯:不难发现:要么拿一个,要么拿一堆。我们考虑一个区间 \(dp\),拿一堆的容易处理,而拿一个的就很难设进状态里。
正解:太大的数值我们往往可以把它设计成状态的表达。比如此处,我们定义 \(L_{l,r}\) 为处理区间 \([l,r]\) 先手想赢的最小的 \(a_l\) 的值,同理定义 \(R_{l,r}\),这样我们很巧妙地把数值的变化涵盖在了状态里。转移是平凡的。
#include<bits/stdc++.h>
using namespace std;
#define inf 2e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=105;
int T,n,m,a[N];
long long L[N][N],R[N][N];
inline void solve(){
n=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)L[i][j]=R[i][j]=inf;
for(int i=1;i<=n;i++)L[i][i]=R[i][i]=1;
for(int len=2;len<=n;len++)
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
if(R[l+1][r]>a[r])L[l][r]=1;
else L[l][r]=L[l][r-1]+1+a[r]-R[l+1][r];
if(L[l][r-1]>a[l])R[l][r]=1;
else R[l][r]=R[l+1][r]+1+a[l]-L[l][r-1];
}
puts(L[1][n]<=a[1]?"First":"Second");
}
int main(){
T=read();
while(T--)solve();
return 0;
}
AGC048E Strange Relation
题意:对于序列 \(\{A_n\}\) 和 \(T\) 定义 \(f(A,T)\) 为字典序最大的序列 \(\{x_n\}\) 满足元素非负且对于每个 \(i\in[1,n]\),\(j<i\) 且 \(A_j+Tx_j<A_i+Tx_i\) 的个数恰为 \(x_i\)。
给定元素集合 \(\{B_{i,k}\}\),\(A_i\) 来自于 \(\{B_i\}\),则共有 \(k^n\) 种 \(\{A_n\}\)。对于 \(\forall i\in [1,n]\)求 \(\sum_A f(A,T)_i\bmod 10^9+7\)。\(k,n\leqslant 50,T\leqslant 10^7,B_{i,j}\leqslant 10^9\)
瞎扯:银牌题我能瞎扯些啥啊/kk……你考虑字典序最大其实就是贪心地选,所以每个数只与前面的有关,与后面的无关。
正解:首先发现你只要合法地填它总是合法的(雾)。考虑一些牛逼东西:若 \(\exists i>1 A_i+Tx_i\in (A_1-T,A_1]\),那么显然我们找到最左的这样的点加一就行。
否则我们视为删除 \(1\) 号点,此时只用将 \(\forall j>1,A_j+Tx_j>A_1:x_j\leftarrow x_j-1\),而由于之前那个限制,这个生成的 \(\{x_n\}\) 也是满足条件的。
也就是说我们可以这样生成 \(\{x_n\}\):从后往前加入 \(x_i\),并把 \(\forall j>i,A_j+Tx_j>x_i\) 的 \(x_j\) 加一,这就是我们之前剥头的逆过程。直接 \(dp\) 即可。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
#define ll long long
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=55;
int n,k,t,b[N][N],dp[N][N],pw[N]={1};
inline void add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);}
int main(){
n=read(),k=read(),t=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)b[i][j]=read();
for(int i=1;i<=n;i++)pw[i]=1ll*pw[i-1]*k%mod;
for(int i=1;i<=n;i++){
int sum=0;
for(int k1=1;k1<=k;k1++){
memset(dp,0,sizeof(dp));
dp[i][0]=pw[n-i];
for(int j=i-1;j>=1;j--)
for(int k2=1;k2<=k;k2++)
for(int p=0;p<=n;p++)
if(b[j][k2]<b[i][k1]+1ll*t*(p+1))add(dp[j][p+1],dp[j+1][p]);
else add(dp[j][p],dp[j+1][p]);
for(int j=0;j<=n;j++)
sum=(sum+1ll*dp[1][j]*j)%mod;
}printf("%d\n",sum);
}
return 0;
}