E - Lucky 7 Battle

​ 经典倒序 d p dp dp,类似求期望,玩游戏的dp题,一般为倒序,因为本题只要求是否为 7 7 7的倍数,所以我们可以开个二维维护每一轮的模 7 7 7的情况,即 d p [ i ] [ j ] dp[i][j] dp[i][j]为从第 i i i轮结束后最终的情况。

初始化为 d p [ n ] [ 0 ] = 1 dp[n][0]=1 dp[n][0]=1,因为第 n n n轮结束后余数为 0 0 0必胜。

然后根据提意转移,分两种情况。

bool x=dp[i][(j*10+a[i]-'0')%7],y=dp[i][j*10%7];
			if(b[i]=='T') dp[i-1][j]=x|y;
			else dp[i-1][j]=x&y;

code

// Problem: E - Lucky 7 Battle
// Contest: AtCoder - Panasonic Programming Contest (AtCoder Beginner Contest 195)
// URL: https://atcoder.jp/contests/abc195/tasks/abc195_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Date: 2021-03-14 16:14:30
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=2e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]); 
}
int n;
char a[N],b[N];
bool dp[N][7];
int main(){
	scanf("%d%s%s",&n,a+1,b+1);
	dp[n][0]=true;
	for(int i=n;i;i--)
		for(int j=0;j<7;j++){
			bool x=dp[i][(j*10+a[i]-'0')%7],y=dp[i][j*10%7];
			if(b[i]=='T') dp[i-1][j]=x|y;
			else dp[i-1][j]=x&y;
		}
	puts(dp[0][0]?"Takahashi":"Aoki");
	return 0;
}

F - Coprime Present

数论&状压dp

一个重要的性质: g c d ( a , b ) = g c d ( a − b , b ) , ( a > b ) gcd(a,b)=gcd(a-b,b),(a>b) gcd(a,b)=gcd(ab,b),(a>b)

也就是辗转相除法。

所以 g c d ( a , b ) ≤ ( B − A ) ≤ 72 gcd(a,b)\le (B-A)\le 72 gcd(a,b)(BA)72

所以答案集合包含 [ 1 , 72 ] [1,72] [1,72]范围的质因数每个最多出现一次,如果出现两次 g c d > 1 gcd>1 gcd>1

[ 1 , 72 ] [1,72] [1,72]的质因数只有20个,所以可以进行状压,令 d p [ i ] dp[i] dp[i]表示状态 i i i的质因数对应的集合个数。

然后用 [ A , B ] [A,B] [A,B]进行转移即可。

时间复杂度: O ( 72 × 2 π ( 72 ) ) O(72\times 2^{\pi(72)}) O(72×2π(72))

code

// Problem: F - Coprime Present
// Contest: AtCoder - Panasonic Programming Contest (AtCoder Beginner Contest 195)
// URL: https://atcoder.jp/contests/abc195/tasks/abc195_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Date: 2021-03-14 16:36:31
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]); 
}
bitset<N>vis;
int p[N],cnt;
void ss(int n){
	vis[0]=vis[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]) p[++cnt]=i;
		for(int j=1;j<=cnt&&i*p[j]<=n;j++){
			vis[i*p[j]]=1;
			if(i%p[j]==0) break;
		}
	}
}
ll dp[1<<20];
int main(){
	ss(72);
	ll A,B;scanf("%lld%lld",&A,&B);
	dp[0]=1;
	//Print(p,cnt);
	for(ll i=A;i<=B;i++){
		int msk=0;
		for(int j=1;j<=cnt;j++) if(i%p[j]==0) msk|=(1<<(j-1));
		for(int j=0;j<(1<<cnt);j++)
			if(!(msk&j)) dp[msk|j]+=dp[j];
	}
	ll s=0;
	for(int i=0;i<(1<<cnt);i++) s+=dp[i];
	printf("%lld\n",s);
	return 0;
}