总结
第二次比赛在配合与节奏上稍微比第一次有了较大的进步,所谓一回生二回熟,大概就是这样吧。但是,问题同样很明显,首先就我而言1、我打题的准确率不够高,一道题要重复交好几遍,即使我知道这只是碰运气……2、算法能力较差,有点拖累了队友的感觉 3、代码实现能力仍有待加强
Rikka with Nash Equilibrium (dp)
description
给定n,m(<80),求一个满足纳什平衡点只有一个的矩形,一个点是纳什平衡当且仅当:
solution
看到题目dp走起,我们从大到小开始放数,设f[k][i][j]表示当前排了i行j列,占用了其中k个位置,f[k][i][j]可转移至f[k+1][i][j],f[k+1][i+1][j],f[k+1][i][j+1]分别表示放入原矩阵i*j,新开一行或新开一列,由于都是从大到小放,而且新开得到行列都基于原来的行列,故纳什平衡点不会增加
code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rp(i,a,b) for(int i=a;i>=b;i--)
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
#define ll long long
using namespace std;
ll dp[85][85][2];
int main()
{
ll n,m,mo;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&n,&m,&mo);
memset(dp,0,sizeof(dp));
dp[1][1][1]=n*m%mo;
int flag=1;
ll ans=0;
for(ll k=2;k<=n*m;k++)
{
flag=1-flag;
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=m;j++)
{
dp[i][j][flag]=0;
if(k>i*j)continue;
dp[i][j][flag]=dp[i][j][1-flag]*(i*j-k+1)%mo;
dp[i][j][flag]=(dp[i][j][flag]+dp[i-1][j][1-flag]*(n-i+1)%mo*j)%mo;
dp[i][j][flag]=(dp[i][j][flag]+dp[i][j-1][1-flag]*(m-j+1)%mo*i)%mo;
if(k==n*m)ans=(ans+dp[i][j][flag])%mo;
}
}
}
printf("%lld\n",ans);
}
}
B Rikka with Seam (dp)
description
给出一个n*m(<2e3)的01矩阵,要求计算每行选择一个位置删除后构成的不同矩阵的数量,相邻行选择删除的位置不能相差k
solution
设f[i][j]表示删除i行第j个数造成的不同矩阵的个数,g[i][j]表示删除i行第j个数造成的与删除第j-1个数造成的01矩阵完全相同的数量,当a[i][j]!=a[i][j-1]时,g[i][j]=0。 前缀和优化一下即可。
code
#include<bits/stdc++.h>
using namespace std;
const int mo=998244353;
int t,n,m,k;
char s[2010][2010];
long long dp1[2010][2010],dp2[2010][2010];
int main(){
for(int i=0;i<=2000;i++) dp1[1][i]=i;
for(int i=1;i<=2000;i++) dp1[i][0]=dp2[i][0]=0;
cin>>t;
while(t--){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++) scanf("%s",s[i]);
for(int i=1;i<m;i++)
if(s[1][i]==s[1][i-1]) dp2[1][i+1]=1;
else dp2[1][i+1]=0;
dp2[1][1]=0;
for(int i=1;i<=m;i++) dp2[1][i]+=dp2[1][i-1];
for(int i=2;i<=n;i++){
for(int j=1;j<=m;j++){
dp1[i][j]=(dp1[i-1][min(j+k,m)]-dp1[i-1][max(j-k-1,0)]-(dp2[i-1][min(j+k,m)]-dp2[i-1][max(j-k,0)])+2*mo)%mo;
if(j>=2&&s[i][j-1]==(s[i][j-2])) dp2[i][j]=(dp1[i-1][min(j+k-1,m)]-dp1[i-1][max(j-k-1,0)]-(dp2[i-1][min(j+k-1,m)]-dp2[i-1][max(j-k,0)])+2*mo)%mo;
else dp2[i][j]=0;
}
for(int j=1;j<=m;j++){
dp1[i][j]=(dp1[i][j]+dp1[i][j-1]+mo)%mo;
dp2[i][j]=(dp2[i][j-1]+dp2[i][j]+mo)%mo;
}
}
long long ans=(dp1[n][m]-dp2[n][m]+mo)%mo;
cout<<ans<<endl;
}
return 0;
}
D Rikka with Stone-Paper-Scissors (数学题 结论题)
description
有两个人在玩石头剪刀布,小A有a,b,c个剪刀石头布,小B有A,B,C个剪刀石头布(a+b+c=A+B+C),小A每次随机出,小B可以透视到小A目前有的牌后选择性的出牌。每轮赢者得一分,输者扣一分,问小B的期望得分。
solution
不知道那群大哥是怎么随手写结论的,反正awsl,设f[n][a][b][A][B]表示当前情况的期望,我们假设c最大,那么小B每次肯定出A
我们假设
(别问我怎么来的 ),那么f[1]成立,若f[n]成立,推得f[n+1]也成立,故结论成立
code
#include<bits/stdc++.h>
using namespace std;
const long long mo=998244353;
long long gcd(long long x,long long y){
return y?gcd(y,x%y):x;
}
int main(){
long long q,n,m,t,a,b,c,a1,b1,c1;
cin>>t;
while(t--){
cin>>a>>b>>c>>a1>>b1>>c1;
n=a1*(c-b)+b1*(a-c)+c1*(b-a);
m=a+b+c;
q=gcd(abs(n),m);
n/=q;
m/=q;
if(m==1||n==0) cout<<n<<endl;
else cout<<n<<"/"<<m<<endl;
}
return 0;
}
J Rikka with Time Complexity(模拟)
description
Let fa(n)=log…logn (there are exactly a log in this function, and log uses base 2). And then, for an integer array A, Rikka defines gA(n) in the following way (B is the suffix of A with length |A|−1):
For example,
and
.
Now, given integer arrays A and B, Rikka wants you to compare gA(n) with gB(n). i.e., let k be limn→+∞gA(n)gB(n). If k=0, output −1; if k=+∞, output 1; otherwise output 0.m<=2000)( the length of A and B. <=3)
solution
我们发现 那就很舒服了,我们直接用这种方式展开式子后从小到大排序比较即可。
code
#include<bits/stdc++.h>
using namespace std;
const int N=5;
int read(){
int f=1,s=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='0')f=-1;
for(;c>='0'&&c<='9';c=getchar())s=s*10+c-48;
return f*s;
}
const int oo=0x3f3f3f3f;
struct pp{
int x,y;
pp(int x_,int y_){
x=x_;y=y_;
if(x>y)swap(x,y);
}
};
int cmp(pp a,pp b){
if(a.x<b.x)return 1;
if(a.x>b.x)return -1;
if(a.y<b.y)return 1;
if(a.y>b.y)return -1;
return 0;
}
struct qq{
int a[N];
int len;
void in(){
for(int i=1;i<=len;i++)a[i]=read();
for(int i=len+1;i<=3;i++)a[i]=oo;
}
}a,b;
int work(){
a.len=read();b.len=read();
a.in();b.in();
pp t1{a.a[1]+2,oo};
pp t2{a.a[2]+1,a.a[3]};
pp t3{b.a[1]+2,oo};
pp t4{b.a[2]+1,b.a[3]};
if(cmp(t1,t2)==-1)swap(t1,t2);
if(cmp(t3,t4)==-1)swap(t3,t4);
if(cmp(t1,t3))return cmp(t1,t3);
else return cmp(t2,t4);
}
int main(){
int T=read();
while(T--){
printf("%d\n",work());
}
return 0;
}
K Rikka with Badminton (数学题)
description
打羽毛球,设a个人只有啥都没有,b人只有拍,c个人只有球,d个人有球有拍,现在要挑一些人加入一个社团,要求这些人中至少有两个人有拍,1个人有球,问组建失败的方案数。
solution
话说好险你们不在我们村,有人带拍不带球,有人带球不带拍,还有人啥都不带,有这么打羽毛球的吗!
这不是高中数学题吗?我们枚举有球有拍的人的个数,当有0人时方案为 最后答案乘上 即可
code
#include<bits/stdc++.h>
using namespace std;
const long long mo=998244353;
int mi(long long x,long long k){
int ans=1;
while(k!=0){
if(k%2==1) ans=ans*x%mo;
x=x*x%mo;
k=k/2;
}
return ans%mo;
}
int main(){
long long t,a,b,c,d;
cin>>t;
while(t--){
cin>>a>>b>>c>>d;
cout<<((1+b+d)%mo*mi(2,c)%mo+mi(2,b)%mo-(1+b)%mo)%mo*mi(2,a)%mo<<endl;
}
return 0;
}