第二次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=jKj+Kf[i1][k]k=jK+1j+Kg[i1][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=jKj+K1f[i1][k]k=jK+1j+K1g[i1][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每次肯定出Af[n][a][b][A][B]=anf[n1][a1][b][A1][B]+bnf[n1][a][b1][A1][B]+cnf[n1][a][b][A1][B]+cbnf[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(cb)+B(ac)+C(ba)nf[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)=(logn)loglogng[1,2](n)=(logn)^{loglogn} and g[3,1,1](n)=(logloglogn)lognlogng[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

我們發現loggA(n)=gB(n)fA1+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)2c+(2bb1)+d2c(b+1)2^c+(2^b-b-1)+d*2^c最後答案乘上2a2^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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章