24.3.3周报(状压dp)

文章讲述了作者在洛谷平台参与的编程挑战,包括计算两点间路径上的关键点、解决正方形覆盖问题,以及使用状压动态规划方法解决多道题目,涉及交互式题目和模拟算法的应用。
摘要由CSDN通过智能技术生成

星期一:

下午洛谷训练赛

补俩题:

思路:计算u到v的路径数,以及路径上每个点的遍历次数,遍历次数等于路径总数即为关键点

代码如下:

ll n;
int m,u,v;
vector<int>ve[1010],pa;
int cnt[1010];
bool vi[1010];
ll sum,ans;
void dfs(int x){
	if(x==v){
		sum++;
		for(auto i:pa) cnt[i]++;
		return ;
	}
	for(auto i:ve[x]){
		if(!vi[i]){
			vi[i]=1,pa.push_back(i);
			dfs(i);
			vi[i]=0,pa.pop_back();
		}
	}
}
void solve(){
	cin >> n >> m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin >> u >> v;
		ve[u].push_back(v);
		ve[v].push_back(u);
	}
	cin >> u >> v;
	dfs(u);
	if(sum>0){
		for(int i=1;i<=n;i++)
			if(cnt[i]==sum) ans++;
		cout << ans-1;
	}else cout << "-1";
	return ;
}

   数正方形:

思路:一个长度为k的框,正方形顶点全在框上的情况有k种, 长度为n的大框,包含长为i的小框有       (n-i+1)^2个

代码如下:

ll n;
ll ans;
void solve(){
	cin >> n;n--;
	for(int i=1;i<=n;i++) ans=(ans+(n-i+1)*(n-i+1)*i)%mod;
	cout << ans;
}

星期二:

打了cf round929 div3, a-e题都很简单,手速还行

星期三:

pta上的训练赛,怎么全是模拟啊

星期四:

入门状压dp (小国王)(洛谷P1896)传送门

代码如下:

int n;
int k,cnt;
int s[1<<12],num[1<<12];
ll dp[12][144][1<<12];
void solve(){
	cin >> n >> k;
	for(int i=0;i<(1<<n);i++){
		if(!(i&i<<1)){
			s[cnt++]=i;                                 //不要用++cnt
			for(int j=0;j<n;j++) num[i]+=(i>>j&1);
		}
	}
	dp[0][0][0]=1;
	for(int i=1;i<=n+1;i++){
		for(int j=0;j<=k;j++){
			for(int a=0;a<cnt;a++){
				for(int b=0;b<cnt;b++){
					int c=num[s[a]];
					if(j<c || s[a]&s[b] || s[a]&(s[b]<<1) || s[a]&(s[b]>>1)) continue;
					dp[i][j][a]+=dp[i-1][j-c][b];
				}
			}
		}
	}
	cout << dp[n+1][k][0];
}

晚上cf睡过头了, 醒来34分, 脑袋迷糊没敢入场,a,b写了后发现C是道交互, 还好

星期五:

cf round931 div2的C又是交互,做不来,还好前俩题手速够快

星期六:

发车2min前上火车,刺激

前所未有的高度,开心

状压dp,玉米田 b站传送门

代码如下:

ll n;
int m;
int s[1<<14],g[14],cnt;
ll dp[20][1<<14];
void solve(){
	cin >> n >> m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			int x; cin >> x;
			g[i]=(g[i]<<1)+x;
		}
	}
	for(int i=0;i<(1<<m);i++){
		if(!(i&(i<<1))) s[cnt++]=i;
	}
	dp[0][0]=1;
	for(int i=1;i<=n+1;i++){
		for(int a=0;a<cnt;a++){
			for(int b=0;b<cnt;b++)
				if((s[a]&g[i])==s[a] && !(s[a]&s[b])) dp[i][a]+=dp[i-1][b];
		}
	}
	cout << dp[n+1][0];
}

周日:

状压dp 炮兵部队 洛谷传送门

代码如下:

ll n;
int m;
int g[110],s[1<<12],cnt,num[1<<12];
ll dp[2][1<<12][1<<12];                            //滚动
void solve(){
	cin >> n >> m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			char x; cin >> x;
			if(x=='P') x='1';
			else x='0';
			g[i]=(g[i]<<1)+x-'0';
		}
	}
	for(int i=0;i<(1<<m);i++){
		if(!(i&i<<1) && !(i&i<<2)){
			s[cnt++]=i;
			for(int j=0;j<m;j++) num[i]+=(i>>j&1);
		}
	}
	for(int i=1;i<=n+2;i++){
		for(int a=0;a<cnt;a++){
			for(int b=0;b<cnt;b++){
				for(int c=0;c<cnt;c++){
					int d=num[s[a]];
					if((s[a]&g[i])!=s[a] || (s[b]&g[i-1])!=s[b] 
                    || s[a]&s[b] || s[a]&s[c] || s[b]&s[c]) continue;
					dp[i&1][b][a]=max(dp[i-1&1][c][b]+d,dp[i&1][b][a]);
				}
			}
		}
	}
	cout << dp[n+2&1][0][0];
}

状压dp 国际象棋 洛谷传送门

代码如下:

ll n;
int m,k;
int num[1<<6];
ll dp[110][30][1<<6][1<<6];                        //开1<<8会mle
void solve(){
	cin >> m >> n >> k;
	for(int i=0;i<(1<<m);i++){
		for(int j=0;j<m;j++) num[i]+=(i>>j&1);     //单行内所有状态合法
	}
	dp[0][0][0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=k;j++){
			for(int a=0;a<(1<<m);a++){
				for(int b=0;b<(1<<m);b++){
					for(int c=0;c<(1<<m);c++){
						int d=num[a];
						if(j<d || a&b<<2 || a&b>>2 || a&c<<1 || a&c>>1
							|| b&c<<2 || b&c>>2) continue;
						dp[i][j][b][a]=(dp[i][j][b][a]+dp[i-1][j-d][c][b])%mod;
					}
				}
			}
		}
	}
	ll ans=0;
	for(int i=0;i<(1<<m);i++){
		for(int j=0;j<(1<<m);j++)
			ans=(ans+dp[n][k][i][j])%mod;
	}
	cout << ans;
//	cout << dp[n+2][k][0][0];                    //因为mle所以开不了n+2
}

cf round931 div2 C题(交互 找矿

思路:先问三个边角,得到三条线的范围,两个交点中必含一矿

代码如下:

ll n;
int m;
int ask(int x,int y){
	cout << "? " << x << " " << y << endl;
	int res; cin >> res;
	return res;
}
void solve(){
	cin >> n >> m;
	int a=ask(1,1);
	int b=ask(n,1);
	int c=ask(1,m);
	int x1=(a-b+n+1)/2,y1=(a+b-n+3)/2;
	int x2=(a+c-m+3)/2,y2=(a-c+m+1)/2;
	if(x1>=1 && x1<=n && y1>=1 && y1<=m && !ask(x1,y1)){
		cout << "! " << x1 << " " << y1 << endl;
	}else{
		cout << "! " << x2 << " " << y2 << endl;
	}
}

如最后的判断写成这样就会wa:(但尚不知晓原因)

    if(x1>=1 && x1<=n && y1>=1 && y1<=m && ask(x1,y1)){
		cout << "! " << x2 << " " << y2 << endl;
	}else{
		cout << "! " << x1 << " " << y1 << endl;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值