专栏文章

以 P7147 为例,记录一下 MatrixGroup 的当前码风

个人记录参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@minl2b32
此快照首次捕获于
2025/12/02 04:09
3 个月前
此快照最后确认于
2025/12/02 04:09
3 个月前
查看原文
CPP
#include <bits/stdc++.h>
#define rep(i,n) for(int i=0,del##i##verme=int(n);i<del##i##verme;++i)
#define rep1(i,n) for(int i=1,parano##i##a=int(n);i<=parano##i##a;++i)
#define per(i,n) for(int i=int(n)-1;i>=0;--i)
#define per1(i,n) for(int i=int(n);i>=1;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define y0 LingLuo
#define y1 VividCycle
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using namespace std;
const ll mod1=998244353;
const ll mod2=1000000007;
unsigned time_related_rand()
{
	return unsigned(std::chrono::steady_clock::now().time_since_epoch().count());
}
const int clockwise=0,counterclockwise=1;
const string hai_name[37]={
"1M","2M","3M","4M","5M","6M","7M","8M","9M",
"1P","2P","3P","4P","5P","6P","7P","8P","9P",
"1S","2S","3S","4S","5S","6S","7S","8S","9S",
"E","S","W","N","B","F","Z","DOUBLE","REVERSE","PASS"};
const int type[37]={
0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,4,5,6};
const int val[37]={
1,2,3,4,5,6,7,8,9,
1,2,3,4,5,6,7,8,9,
1,2,3,4,5,6,7,8,9,
101,104,107,110,113,116,119,0,0,0};
int cnt[38];
bool agari_without_atama_chinitsu(int *valt)
{
	int p=0,q=0;
	rep(i,9)
	{
		if(valt[i]<p+q) return false;
		int c=valt[i]-p-q;
		p=q;q=c%3;
	}
	return p==0&&q==0;
}
bool agari_without_atama()
{
	for(int i=27;i<34;++i) if(cnt[i]%3) return false;
	return agari_without_atama_chinitsu(cnt)
	&&agari_without_atama_chinitsu(cnt+9)
	&&agari_without_atama_chinitsu(cnt+18);
}
bool agari(vector<int> vc)
{
	if(int(vc.size())%3!=2)
	{
		cout<<"WHY DO I NEED DETERMINE WHETHER A TEHAI WITH "<<vc.size()<<" HAI(S) IS AGARI?"<<endl;
		exit(-1);
	}
	sort(vc.begin(),vc.end());
	if(vc.back()>=34) return false;
	memset(cnt,0,sizeof(cnt));
	for(int x:vc) ++cnt[x];
	rep(i,34) if(cnt[i]>=2)
	{
		cnt[i]-=2;
		if(agari_without_atama()) return true;
		cnt[i]+=2;
	}
	return false;
}
int dp[2][5][3][3],nw[2][5][3][3];
int shantensu(vector<int> vc)
{
	int n=int(vc.size())/3;
	memset(cnt,0,sizeof(cnt));
	for(int x:vc) ++cnt[x];
	memset(dp,0x3f,sizeof(dp));
	dp[0][0][0][0]=0;
	rep(i,34)
	{
		memset(nw,0x3f,sizeof(nw));
		rep(j,2) rep(k,n+1) rep(l,3) rep(m,3) if(dp[j][k][l][m]!=0x3f3f3f3f)
		{
			for(int c=l+m;c<=4;++c)
			{
				int need=max(0,c-cnt[i]);
				int rest=c-l-m;
				if(k+l+m+rest%3+rest/3<=n)
				nw[j][k+l+rest/3][m][rest%3]=min(nw[j][k+l+rest/3][m][rest%3],dp[j][k][l][m]+need);
				if(j==0&&rest>=2&&k+l+m+rest-2<=n)
				nw[1][k+l][m][rest-2]=min(nw[1][k+l][m][rest-2],dp[0][k][l][m]+need);
			}
		}
		if(val[i]==9||type[i]==3)
		{
			memset(dp,0x3f,sizeof(dp));
			rep(j,2) rep(k,5) dp[j][k][0][0]=nw[j][k][0][0];
		}
		else
		{
			memcpy(dp,nw,sizeof(dp));
		}
	}
	return dp[1][n][0][0];
}
const char player_name[4]={'A','B','C','D'};
const int no_buff=0,skipped=1,no_draw=2;
int state[4]={0,0,0,0};
int direction=clockwise,current_player=0;
const int nxt[2][4]={1,2,3,0,3,0,1,2};
vector<int> tehai[4];int shanten[4];
vector<int> temp;
void draw()
{
	cout<<"DRAW"<<endl;
	exit(0);
}
void calcshanten(int player)
{
	shanten[player]=shantensu(tehai[player]);
}
void selfdrawn(int player)
{
	cout<<player_name[player]<<" SELFDRAWN"<<endl;
	cout<<player_name[player]<<" WIN"<<endl;
	exit(0);
}
void ron(int player)
{
	cout<<player_name[player]<<" RON"<<endl;
	cout<<player_name[player]<<" WIN"<<endl;
	exit(0);
}
int counter;
void drawcard(int player)
{
	if(counter==148)
	{
		draw();
	}
	string st;cin>>st;++counter;
	int x=0;rep(i,37)if(st==hai_name[i]){x=i;break;}
	tehai[player].pb(x);
	cout<<player_name[player]<<" IN "<<st<<endl;
}
void play(int player,int card)
{
	tehai[player].erase(find(tehai[player].begin(),tehai[player].end(),card));
	if(card!=36)
	cout<<player_name[player]<<" OUT "<<hai_name[card]<<endl;
	else
	cout<<player_name[player]<<" OUT "<<hai_name[card]<<" "<<
	player_name[nxt[direction][current_player]]<<endl;
}
bool check_furo(int player,int card,int w1,int w2,string furo_type)
{
	temp=tehai[player];
	vector<int>::iterator itr=find(temp.begin(),temp.end(),w1);
	if(itr==temp.end()) return false;
	temp.erase(itr);
	itr=find(temp.begin(),temp.end(),w2);
	if(itr==temp.end()) return false;
	temp.erase(itr);
	int stv=shantensu(temp);
	if(stv>=shanten[player]) return false;
	tehai[player]=temp;shanten[player]=stv;
	if(card<w1) swap(card,w1);
	if(card>w2) swap(card,w2);
	cout<<player_name[player]<<" "<<furo_type<<" "<<hai_name[w1]<<" "<<
	hai_name[card]<<" "<<hai_name[w2]<<endl;
	return true;
}
void tsuzuku()
{
	current_player=nxt[direction][current_player];
}
int to_play()// nankiru
{
	int x=114541,ret=0;
	rep(i,tehai[current_player].size())
	{
		if(i==0||tehai[current_player][i]!=tehai[current_player][i-1])
		{
			temp=tehai[current_player];temp.erase(temp.begin()+i);
			int z=shantensu(temp);
			if(z<=x)
			{
				x=z;ret=tehai[current_player][i];
			}
		}
	}
	return ret;
}
int main()
{
	rep(i,13)
	{
		drawcard(0);drawcard(1);drawcard(2);drawcard(3);
	}
	rep(i,4) calcshanten(i);
	while(1)
	{
		if(state[current_player]==skipped)
		{
			state[current_player]=no_buff;
			tsuzuku(); 
			continue;
		}
		if(state[current_player]==no_buff)
		{
			drawcard(current_player);
		}
		state[current_player]=no_buff; 
		sort(tehai[current_player].begin(),tehai[current_player].end());
		if(agari(tehai[current_player]))
		{
			selfdrawn(current_player);
		}
		if(tehai[current_player].back()==36)// pass
		{
			play(current_player,36);
			state[nxt[direction][current_player]]=skipped;
			calcshanten(current_player);
			tsuzuku(); 
			continue;
		}
		if(tehai[current_player].back()==35)// reverse
		{
			play(current_player,35);
			direction^=1;
			calcshanten(current_player);
			tsuzuku(); 
			continue; 
		}
		if(tehai[current_player].back()==34)// double
		{
			play(current_player,34);
			calcshanten(current_player);
			continue;
		}
		int sutehai=to_play();
		play(current_player,sutehai);
		calcshanten(current_player);
		int potential_ron=nxt[direction][current_player];
		while(potential_ron!=current_player)
		{
			temp=tehai[potential_ron];temp.pb(sutehai);
			if(agari(temp))
			{
				ron(potential_ron);
			}
			potential_ron=nxt[direction][potential_ron];
		}
		bool flag=false;
		rep(i,4) if(i!=current_player&&check_furo(i,sutehai,sutehai,sutehai,"PONG"))
		{
			current_player=i;state[i]=no_draw;
			flag=true;break;
		}
		if(flag) continue;
		if(type[sutehai]<=2)
		{
			int nxt_player=nxt[direction][current_player];
			int value=val[sutehai];
			if(value<=7&&check_furo(nxt_player,sutehai,sutehai+1,sutehai+2,"CHOW"))
			{
				current_player=nxt_player;state[current_player]=no_draw;
				continue;
			}
			if(value<=8&&value>=2&&check_furo(nxt_player,sutehai,sutehai-1,sutehai+1,"CHOW"))
			{
				current_player=nxt_player;state[current_player]=no_draw;
				continue;
			}
			if(value>=3&&check_furo(nxt_player,sutehai,sutehai-2,sutehai-1,"CHOW"))
			{
				current_player=nxt_player;state[current_player]=no_draw;
				continue;
			}
		}
		tsuzuku();
	}
	return 0;
}
/* things to check
1.  int overflow or long long memory need
2.  recursion/array/binary search/dp/loop bounds
3.  precision
4.  special cases(n=1,bounds)
5.  delete debug statements
6.  initialize(especially multi-tests)
7.  = or == , n or m ,++ or -- , i or j , > or >= , < or <=
8.  keep it simple and stupid
9.  do not delete, use // instead
10. operator priority
11. is there anything extra to output?
12. ...
*/

/* something to think about
1. greedy? dp? searching? dp with matrix/ segment tree? binary search?
2. If contains "not", why not ?????? or few affect?
*/
稍微解释一下,如果一行代码在编辑器里超过一行了就会分行。
其它的看之前

评论

1 条评论,欢迎与作者交流。

正在加载评论...