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;
}

可以借鉴的博客

posted @ 2022-07-13 00:33  syzf2222  阅读(63)  评论(0编辑  收藏  举报