Codeforces Round 861 (Div. 2)

Codeforces Round 861 (Div. 2)
C题直接数位dp即可

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<bitset>
#include<cmath>
#include<set>
#include<unordered_map>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define mk(x,y) make_pair((x),(y))
#define A puts("Yes")
#define B puts("No")
using namespace std;
typedef double db;
typedef long long ll;
//typedef __int128 i128;
const int N=1e6+5;
const int S=1e5+5;
const ll inf=1ll<<60;
const ll mo=1e9+7;
ll l,r,d1[N],d2[N],t,l1,l2,u,d,ans;
ll f[20][2][2][2],flag,c[100];
void check(){
	memset(f,-1,sizeof(f));
	
	f[l1][1][1][1]=0;
	
	int aa,bb,ne;
	fd(i,l1-1,0) {
		fo(le,0,1) fo(a,0,1) fo(b,0,1) fo(dig,d,u) {
			if (a && dig<d1[i]) continue;
			if (b && dig>d2[i]) continue;
			if (f[i+1][le][a][b]<0) continue;
			
			aa=a&(dig==d1[i]);
			bb=b&(dig==d2[i]);
			ne=le&(dig==0);
		
			
			f[i][ne][aa][bb]=f[i+1][le][a][b]+dig*c[i];
		}
	}
	
	fo(a,0,1) fo(b,0,1) {
		if (f[0][0][a][b]>0) {
			flag=1;
			ans=f[0][0][a][b];
			return;
		}
	}
}
void solve(){
	flag=0;
	fo(i,0,9) {
		fo(j,0,9) {
			d=j;
			u=j+i;
			
			if (u>9) break;
			
			check();
			if (flag) return;
		}
	}
}
int main()
{
//	freopen("data.in","r",stdin);
	
	c[0]=1;
	fo(i,1,18) c[i]=c[i-1]*10ll;
	
	int T;
	scanf("%d",&T);
	while (T--) {
		scanf("%lld %lld",&l,&r);
		
		l1=l2=0;
		t=l; 
		while (t) {
			d1[l1++]=t%10;
			t/=10;
		}
		
		t=r;
		while (t) {
			d2[l2++]=t%10;
			t/=10;
		}
		
		if (l1<l2) {
			ll z=0;
			while (z<l) z=z*10ll+9ll;
			printf("%lld\n",z);
			continue;
		}
		
		solve();
		printf("%lld\n",ans);
	}

	return 0;
}

	
 

D
题意:一个长度为k的序列的价值定义为将其修改为回文的最少步数。求一个串所有长度为k的字串的价值和。

首先注意到一个pair(i,j)产生了贡献,i,j的奇偶性一定相同。
然后问题转化为询问一段区间[l,r](只考虑与i奇偶性相同的)中有多少个数和a[i]相同
那么我们可以离线处理,从左往右扫,利用前缀相减就能得到。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<bitset>
#include<cmath>
#include<set>
#include<unordered_map>
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (ll (i)=(b);(i)>=(a);(i)--)
#define mk(x,y) make_pair((x),(y))
#define A puts("Yes")
#define B puts("No")
using namespace std;
typedef double db;
typedef long long ll;
//typedef __int128 i128;
const int N=1e6+5;
const int S=1e5+5;
const ll inf=1ll<<60;
const ll mo=1e9+7;
struct node{
	ll x,op;
};
vector<node> v[N];
ll n,a[N],k,ans,l,r;
ll f[N],g[N];

int main()
{
//	freopen("data.in","r",stdin);
	
	scanf("%lld %lld",&n,&k);
	if (k==1) {
		printf("%d\n",0);
		return 0;
	}
	fo(i,1,n) scanf("%lld",&a[i]);
	
	fo(i,k/2+2, n)  {
		l=max(2*(1+k/2)-i, i+1-k);
		r=min(i-2, 2*(n-k/2)-i);
		if ((i-l)&1) l++;
		if ((r-i)&1) r--;
		
		ans+=(r-l)/2+1ll;
//		printf("%lld %lld %lld\n",i,l,r);
		if (l-2>0) v[l-2].push_back((node){a[i], +1}); 
		v[r].push_back((node){a[i], -1});
	}
	
	fo(i,1,n) {
		if (i&1) {
			f[a[i]]++;
			for (int j=0;j<(int)v[i].size();j++) {
				ans+=v[i][j].op*f[v[i][j].x];
			}
		}
		else {
			g[a[i]]++;
			for (int j=0;j<(int)v[i].size();j++) {
				ans+=v[i][j].op*g[v[i][j].x];
			}
		}
	}

	printf("%lld",ans);
	return 0;
}

	
 

E题:
数的范围是在k进制下的n位数
一个数是lucky的当且仅当在k进制下,存在一个数位上的数,等于其他数位上的数在模k意义下的和。

利用减法原理
假设一个数的数位和为s,如果存在一个数,那么有
s-x%k=x%k -> s%k=2x%k
那么我们找到这样的x,就是说在计算和为s的方案数是不能使用这些x

easy直接dp即可
mid可以将其看作是一个卷积。

posted @ 2024-01-17 08:47  gan_coder  阅读(11)  评论(0)    收藏  举报