ACM2020两小时训练补题题解

ACM2020两小时训练补题题解

A - Dice Sum

题意:给定 n, m, k ,分别代表需要的数字数量、从1-m中选,总和要小于等于k,且同一数字可多次重复选择。

正解:背包求解,每次要将一个数字放到背包中。如此循环下去,将所有可能全部求解。

状态:dp[i] [j] 代表 选择了i个数,其总和等于k的序列数量。

初始状态:dp[0] [0]=1;0个数 总和等于0 的序列只有一种情况。

状态转移方程:每次要放进去一个数,背包容量是从1-k,然后看 可以把哪个数放进去,从1-m遍历,如果其值小于等于背包的容量,说明该值可以放到背包中去。

for(int i=1;i<=n;i++){//总共要放入n个数
		for(int j=1;j<=k;j++){//背包总容量不能超过k
			for(int u=1;u<=m;u++){//可以选择的数的范围是从1-m
				if(j>=u){//若是可以将该数放入到背包中
					dp[i][j]=(dp[i][j]+dp[i-1][j-u])%mod;//状态转移方程
				} 
			} 
		}
	}
#include <iostream>
#include <cstring>
using namespace std;
typedef long long int ll;
ll mod=998244353;
ll dp[55][2505];
int main() {
	int n,m,k;
	memset(dp,0,sizeof(dp));
	scanf("%d%d%d",&n,&m,&k);
	dp[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=k;j++){
			for(int u=1;u<=m;u++){
				if(j>=u){
					dp[i][j]=(dp[i][j]+dp[i-1][j-u])%mod;
				} 
			} 
		}
	}
	ll sum=0;
	for(int i=1;i<=k;i++){
		sum=(sum%mod+dp[n][i]%mod)%mod;
	}
	cout<<sum<<endl;
}

C - K-colinear Line

题意:给定N个点的x,y坐标,K,求解有多少条不重复的直线,穿过这些点的个数>=min(n,k)。

题解:暴力搜索,三重循环,并标记一条线上重复的点。

知识点:判断两个向量是否平行,可通过向量运算进行,x1*y2==x2 *y1 可判断两条向量平行。

​ 向量n1,n2 夹角判断:n1*n2=|n1| * |n2| *cos ;

#include <iostream>
#include <map>
#include <vector>
#include <set>
using namespace std;
class node{
	public:
		int x,y;
};
node no[305];
bool fi(int i,int j,int k){
	int y1=no[j].y-no[i].y;
	int x1=no[j].x-no[i].x;
	int y2=no[k].y-no[i].y;
	int x2=no[k].x-no[i].x;
	if(x1*y2-x2*y1==0)return true;
	return false;
}
int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++){
		scanf("%d%d",&no[i].x,&no[i].y);
	}
	if(k==1){
		cout<<"Infinity"<<endl;
		return 0;
	}
	int sum=0;
	map<pair<int,int>,bool>mp;
	for(int i=0;i<n-1;i++){
		for(int j=i+1;j<n;j++){
			if(mp.find(make_pair(i,j))!=mp.end())continue;
			set<int>st;
			bool f=0;
			for(int w=j;w<n;w++){
				if(fi(i,j,w)){
					st.insert(i);
					st.insert(j);
					st.insert(w);
				}
			}
			int t=st.size();
			if(st.size()>=min(n,k)){
				sum++;//,cout<<' '<<i<<" "<<j<<endl;
			}
			set<int>::iterator it1,it2,it3;
			it3=st.end();
			it3--;
			for(it1=st.begin();it1!=it3;it1++){
				it2=it1;
				it2++;
				for(;it2!=st.end();it2++){
					mp[make_pair(*it1,*it2)]=1;
				}
			}
		}
	}
	cout<<sum<<endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值