洛谷P3413 P6754

雙倍經驗題ios

因爲我先作的 P6754,因此一切思路基於 P6754 的題目spa

「 P6754 這題就是 P3413 的究極弱化版 」 --By Aliemo.code


P6754 Description

在給定的 \([a,b]\) 區間內求長度 \(\ge\) \(2\) 的非迴文串的個數ip


Solution

\(f[i][j][k]\) 表示長度爲 \(i\),最高位爲 \(j\) ,次高位爲 \(k\) 的非迴文串的個數ci

顯然有狀態轉移方程式字符串

\[f[i][j][k]=\sum_{j/k/l=0}^9f[i-1][k][l]\mid j!=k\&\&j!=l\&\&k!=l \]

對於答案的統計,就是在求出全部的非迴文串個數後,經過給定的邊界來判斷get

對於 \(ans_{l,r}\) 能夠轉化爲 \(ans_{1,r}-ans_{1,l-1}\)string


注意,本題的求解,對於區間端點的處理,最好將其轉化爲字符串操做it

便於求非迴文串的個數io

像這樣

for(int i = len;i >= 1;i --) {
    a[i] = x[len - i] - '0';
    sum = sum * 10 + a[i];
}

其餘的注意事項放在代碼裏


Code

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#define int long long
#define rr register

using namespace std;

char A[1010],B[1010];
int f[1010][20][20]; 
int a[1010];

int read(){
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') w=1;ch=getchar();}
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
	return s*w;
}

void init(){
	for(rr int i=2;i<=1000;i++)
		for(rr int j=0;j<=9;j++)
			for(rr int k=0;k<=9;k++){
				if(j==k) continue;
				for(rr int l=0;l<=9;l++)
					if(k!=l&&j!=l) f[i][j][k]+=f[i-1][k][l];// 
				if(i==2) f[i][j][k]++;
			}
}

int solve(char x[]){
	bool t=1;memset(a,0,sizeof a);
	int ans=0,cnt=0,sum=0,len=strlen(x),ll1=-1,ll2=-1;
	for(rr int i=len;i>=1;i--){a[i]=x[len-i]-'0';sum=sum*10+a[i];}
	sum++;ans+=10;if(len==1) return sum;//長度爲 1 的 10 個數直接加//若是長度爲 1 ,不符合規定
	for(rr int i=2;i<len;i++)
		for(rr int j=1;j<=9;j++)//排除前導 0  
			for(rr int k=0;k<=9;k++)
					ans+=f[i][j][k];
	for(rr int i=len;i>=2;i--){
		for(rr int j=0;j<a[i];j++){	
			if(i==len&&j==0) continue;
			for(rr int k=0;k<=9;k++)
				if(j!=k&&ll1!=k&&ll1!=j&&ll2!=j) ans+=f[i][j][k]; 
		}
		if(ll1==a[i]||ll2==a[i]){t=0;break;}//判斷前一位與前兩位 
		ll2=ll1;ll1=a[i];
	}
	if(t==1)for(rr int i=0;i<=a[1];i++)if(i!=ll1&&i!=ll2)ans++;//最後一位單獨處理 
	return ans;
}

signed main(){
	init();cin>>A;cin>>B;
	int Ans=solve(B)-solve(A);
	int len=strlen(A),vis=0;
	for(rr int i=1;i<len;i++)
		if(A[i]==A[i-1]||(A[i]==A[i-2]&&i>1)){vis=1;break;}
	if(!vis) Ans++;printf("%lld",Ans);
	return 0;
}


P3413 Description

在給定的 \([a,b]\) 區間內求長度 \(\ge\) \(2\) 的非迴文串的個數


Solution

按照上面的思路,比較兩位上相同的

比較麻煩

換個角度,若是用總串數減去非迴文串數,那不就是迴文串數了


思考過程與原理同上

注意取模

代碼一改就行


Code

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#define int long long
#define rr register
#define Mod 1000000007

using namespace std;

char A[1010],B[1010];
int f[1010][20][20];
int a[1010];

int read(){
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') w=1;ch=getchar();}
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
	return s*w;
}

void init(){
	for(rr int i=2;i<=1000;i++)
		for(rr int j=0;j<=9;j++)
			for(rr int k=0;k<=9;k++){
				if(j==k) continue;
				for(rr int l=0;l<=9;l++)
					if(k!=l&&j!=l) f[i][j][k]=(f[i][j][k]+f[i-1][k][l])%Mod;
				if(i==2) f[i][j][k]=(f[i][j][k]+1)%Mod;
			}
}

int solve(char x[]){//sum 統計總串數,減去 ans 便可
	bool t=1;memset(a,0,sizeof a);
	int ans=0,cnt=0,sum=0,len=strlen(x),ll1=-1,ll2=-1;
	for(rr int i=len;i>=1;i--){a[i]=x[len-i]-'0';sum=(sum*10+a[i])%Mod;}
	sum++;ans+=10;if(len==1) return 0; 
	for(rr int i=2;i<len;i++)
		for(rr int j=1;j<=9;j++)
			for(rr int k=0;k<=9;k++)
					ans=(ans+f[i][j][k])%Mod;
	for(rr int i=len;i>=2;i--){
		for(rr int j=0;j<a[i];j++){	
			if(i==len&&j==0) continue;
			for(rr int k=0;k<=9;k++)
				if(j!=k&&ll1!=k&&ll1!=j&&ll2!=j) ans=(ans+f[i][j][k])%Mod; 
		}
		if(ll1==a[i]||ll2==a[i]){t=0;break;}
		ll2=ll1;ll1=a[i];
	}
	if(t==1)for(rr int i=0;i<=a[1];i++)if(i!=ll1&&i!=ll2)ans=(ans+1)%Mod; 
	return (sum-ans+Mod)%Mod;
}

signed main(){
	init();cin>>A;cin>>B;	
	int len=strlen(A),Ans=solve(B)-solve(A);
	for(rr int i=1;i<len;i++)
	    if(A[i]==A[i-1]||(A[i]==A[i-2]&&i>1)){Ans=(Ans+1)%Mod;break;}
	printf("%lld",(Ans+Mod)%Mod);
	return 0;
}
相關文章
相關標籤/搜索