AtCoder Beginner Contest 233(C,D,E)

Linking


C - Product

题意:

N N N 个盒子,每个盒子里有 L i Li Li 个球,每个球上写有一个数 a i j aij aij
现在要从每个盒子中都拿出一个球,问一共有多少种方案数使得拿出球上写的数乘积为 X X X
在这里插入图片描述

思路:

思路1:
一共N层,对于每一层的每个数,都遍历上一层更新过后的结果,更新为新的结果,对应方案数也更新。

for(auto it : dp1)
{
	int k=it.first, c=it.second;
	if(x * k <= m) dp2[x*k]+=c;
}

思路2:
暴搜。
从上往下走,每一层遍历拿了哪个数,走到最后判断是否乘积是X。如果是,ans++。
可以剪枝判掉未到最后一层乘积已经大于X的情况。

但是一共N层,层数未知。一共1e5个物品。。
不明白为什么暴搜不会超时,还请清楚的大佬告知!

注意:
数比较大,所以要提前判断乘积之后不会超过X,不超过longlong范围。
要不然会莫名wa两个点。。

Code1:
const int N = 500010, mod = 1e9+7;
int T, n, m;
map<int,int> a[N];
int cnt[N];
int sum=1, ans;

signed main(){
	Ios;
	
	cin>>n>>m;
	map<int,int> dp1, dp2;
	
	for(int i=1;i<=n;i++)
	{
		int cnt;cin>>cnt;
		for(int j=1;j<=cnt;j++)
		{
			int x;cin>>x;
			if(i==1) dp2[x]++;
			for(auto it : dp1)
			{
				int k=it.first, c=it.second;
				if(x * k <= m) dp2[x*k]+=c;
			}
		}
		dp1 = dp2;
		dp2.clear();
	}
	cout<<dp1[m];
Code2:
const int N = 500010, mod = 1e9+7;
int T, n, m;
map<int,int> a[N];
int cnt[N];
int sum=1, ans;

void dfs(int u)
{
	if(u==n+1)
	{
		if(sum==m) ans++;
		return;
	}
	
	for(int i=1;i<=cnt[u];i++)
	{
//		if(((m / sum) % a[u][i]) != 0) continue;
		if(sum*a[u][i]>m) continue;
		
		sum *= a[u][i];
		if(sum <= m && m%sum==0) dfs(u+1);
		sum /= a[u][i];
	}
}

signed main()
{
	cin>>n>>m;
	
	for(int i=1;i<=n;i++)
	{
		cin >> cnt[i];
		for(int j=1;j<=cnt[i];j++)
		{
			cin>>a[i][j];
		}
	}
	
	dfs(1);
	
	cout<<ans;
}

D - Count Interval

题意:

给出长度为 N 的数列,问一共有多少个连续子序列总和为 K?
在这里插入图片描述

思路:

前缀和板子题。
map存储当前位置的前缀和 si 出现的次数。
遍历每个位置,答案ans += mp[si - K]mp[si]++

Code:

map<int,int> mp;

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];

signed main(){
	cin>>n>>m;

	mp[0]=1;
	int sum=0,ans=0;
	for(int i=1;i<=n;i++)
	{
		int x;cin>>x;
		sum+=x;
		ans+=mp[sum-m];
		mp[sum]++;
	}
	cout<<ans;
	
	return 0;
}

E - Σ[k=0…10^100]floor(X/10 ^k)

题意:

在这里插入图片描述
就是给出一个长度不超过 5e5 的数字串,求其每次砍掉末位,所表示出的十进制数之和。
例如:输入:1225, 输出1360。(1225 + 122 + 12 + 1 = 1360)

思路:

这么大的数,肯定不能直接表示。于是很容易想到高精度。。 其实不用。
就像上面的例子,我们看到所有加数的个位上的数为1、2、2、5,所有加数的十位上的数为1、2、2,百位上的数为1、2…
不同位数上的数就是原数对应位置的前缀和。
所以直接模拟一遍加法就可以了。

Code:
const int N = 500010, mod = 1e9+7;
int T, n, m;
int a[N];

signed main(){
	Ios;
	
	string s;
	getline(cin,s);
	
	int len=s.size();
	s=" "+s;
	
	for(int i=1;i<=len;i++) a[i]=a[i-1]+s[i]-'0';
	
	int t=0;
	vector<int> v;
	
	for(int i=len;i>=1;i--)
	{
		int x=t;
		x += a[i];
		v.push_back(x%10);
		t = x/10;
	}
	if(t) cout<<t;
	for(int i=v.size()-1;i>=0;i--) cout<<v[i];
	
	return 0;
}

场上C题没判超范围的情况,卡住了。E题思维没转化过来。。
太菜了。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值