ARC058补题

C.
发现枚举到1e5即可覆盖所有情况。
#include <bits/stdc++.h>
using namespace std;
int n,k,x;
bool vis[10];
int main(){
	scanf("%d%d",&n,&k);
	for (register int i=1; i<=k; ++i)
	{
		scanf("%d",&x);
		vis[x]=true;	
	}
	for (register int i=n; i<=99999; ++i)
	{
		bool jay=true;
		int x=i;
		while (x)
		{
			if (vis[x%10]) {jay=false; break;}
			x/=10;
		}
		if (jay) 
		{
			printf("%d\n",i);
			break;
		}
	}
return 0;	
}
D.
从(x,y)走到(xx,yy)的方案数为C(xx-x,xx-x+yy-y)。
枚举中间点,将整个图分两部分走完。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,MOD=1e9+7;
int n,m,A,B,ans;
int bin[N],inv[N];

inline int pow(int a,int n)
{
	int res=1;
	while (n)
	{
		if (n&1ll) res=res*a%MOD;
		a=a*a%MOD;
		n>>=1ll;
	}
	return res;
}

inline int C(int a,int b)
{
	return bin[a]*inv[a-b]%MOD*inv[b]%MOD;
}

inline int solve(int sx,int sy,int tx,int ty)
{
	return C(tx-sx+ty-sy,tx-sx);
}

signed main(){
	bin[0]=inv[0]=1;
	for (register int i=1; i<=2e5; ++i) bin[i]=bin[i-1]*i%MOD; 
	for (register int i=1; i<=2e5; ++i) inv[i]=pow(bin[i],MOD-2ll);
	scanf("%lld%lld%lld%lld",&n,&m,&A,&B);
	for (register int i=1; i<=n-A; ++i) ans=(ans+solve(1,1,i,B)*solve(i,B+1,n,m)%MOD)%MOD; 
	printf("%lld\n",ans);
return 0;
}
E.
考虑反着做,就不用去重了。
dp[i][p]:前i为填完了,填的数列能构成的数的集合为p。(p中第i位为1,表示数列能构成的数中有i)。
定义sum为符合条件的数列集合。
答案就是10^n减去所有p!=sum的情况。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=1e9+7;
int n,x,y,z,sum,max_statue,ans;
int dp[41][1<<18];
signed main(){
	scanf("%lld%lld%lld%lld",&n,&x,&y,&z);
	sum=1<<(x+y+z-1);
	sum|=1<<(y+z-1);
	sum|=1<<(z-1);
	max_statue=(1<<(x+y+z))-1;
	dp[0][0]=1;
	ans=1;
	for (register int i=1; i<=n; ++i)   //题目要求0->n-1,那么即:1->n 
	{
		ans=ans*10%MOD;
		for (register int p=0; p<=max_statue; ++p)
		if (dp[i-1][p])
		{
			for (register int j=1; j<=10; ++j)
			{
				int now=(p<<j)|(1<<(j-1));
				now&=max_statue;
				if ((now&sum)!=sum) dp[i][now]=(dp[i][now]+dp[i-1][p])%MOD;
			}
		}
	}
	for (register int p=0; p<=max_statue; ++p) ans=(ans-dp[n][p]+MOD)%MOD;
	printf("%lld\n",ans);	
return 0;
}
F.
字符串比较大小无后效性,所以满足当前最优即可。
我们考虑构造k次答案,使得每一次的答案均为当前最优。
#include <bits/stdc++.h>
using namespace std;
const int N=2e3+5,M=1e4+5;
int n,k,cnt,ncnt;
int len[N];
char str[N][M],ans[M];
bitset<M>ok[N];
pair<int,int>p[2][N];
int main(){
	scanf("%d%d",&n,&k);
	for (register int i=1; i<=n; ++i) scanf("%s",str[i]+1),len[i]=strlen(str[i]+1);
	ok[n+1][0]=1;
	for (register int i=n; i>=1; --i) ok[i]=ok[i+1]|(ok[i+1]<<len[i]);
	for (register int i=1; i<=n; ++i)
	if (ok[i+1][k-len[i]]) p[0][++cnt]=make_pair(i,1);
	int now=0;
	for (register int i=1; i<=k; ++i)
	{
		char minn='z';
		for (register int j=1; j<=cnt; ++j) minn=min(minn,str[p[now][j].first][p[now][j].second]);
		ans[i]=minn;
		int head=n+1;
		ncnt=0;
		for (register int j=1; j<=cnt; ++j)
		{
			int id=p[now][j].first,pos=p[now][j].second;
			if (str[id][pos]!=minn) continue;
			if (pos==len[id]) head=min(head,id+1);
			else p[now^1][++ncnt]=make_pair(id,pos+1);
		}
		for (register int j=head; j<=n; ++j)
		if (k-i-len[j]>=0 && ok[j+1][k-i-len[j]]) p[now^1][++ncnt]=make_pair(j,1);
		cnt=ncnt;
		now^=1; 
	}
	puts(ans+1);
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值