第二次icpc集训(Saturday)

总结

第二次比赛在配合与节奏上稍微比第一次有了较大的进步,所谓一回生二回熟,大概就是这样吧。但是,问题同样很明显,首先就我而言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。 f [ i ] [ j ] = k = j K j + K f [ i 1 ] [ k ] k = j K + 1 j + K g [ i 1 ] [ k ] f[i][j]=\sum_{k=j-K}^{j+K}f[i-1][k]-\sum_{k=j-K+1}^{j+K}g[i-1][k] g [ i ] [ j ] = k = j K j + K 1 f [ i 1 ] [ k ] k = j K + 1 j + K 1 g [ i 1 ] [ k ] g[i][j]=\sum_{k=j-K}^{j+K-1}f[i-1][k]-\sum_{k=j-K+1}^{j+K-1}g[i-1][k] 前缀和优化一下即可。

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 [ n ] [ a ] [ b ] [ A ] [ B ] = a n f [ n 1 ] [ a 1 ] [ b ] [ A 1 ] [ B ] + b n f [ n 1 ] [ a ] [ b 1 ] [ A 1 ] [ B ] + c n f [ n 1 ] [ a ] [ b ] [ A 1 ] [ B ] + c b n f[n][a][b][A][B]=\frac{a}{n}f[n-1][a-1][b][A-1][B]+\frac{b}{n}f[n-1][a][b-1][A-1][B]+\frac{c}{n}f[n-1][a][b][A-1][B]+\frac{c-b}{n}
我们假设 f [ n ] [ a ] [ b ] [ A ] [ B ] = A ( c b ) + B ( a c ) + C ( b a ) n f[n][a][b][A][B]=\frac{A(c-b)+B(a-c)+C(b-a)}{n} 别问我怎么来的 ),那么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):
gA(n)={fA1(n)fA1(n)gB(n)|A|=1|A|>1

For example, g [ 1 , 2 ] ( n ) = ( l o g n ) l o g l o g n g[1,2](n)=(logn)^{loglogn} and g [ 3 , 1 , 1 ] ( n ) = ( l o g l o g l o g n ) l o g n l o g n g[3,1,1](n)=(logloglogn)^{logn^{logn}} .
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

我们发现 l o g g A ( n ) = g B ( n ) f A 1 + 1 ( n ) logg_A(n)=g_B(n)*f_{A1+1}(n) 那就很舒服了,我们直接用这种方式展开式子后从小到大排序比较即可。

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人时方案为 ( b + 1 ) 2 c + ( 2 b b 1 ) + d 2 c (b+1)2^c+(2^b-b-1)+d*2^c 最后答案乘上 2 a 2^a 即可

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;
}
发布了257 篇原创文章 · 获赞 451 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/crybymyself/article/details/104951431