11.13考后反思

T1 数位

题面

有一个正整数 \(D\) 和一个长为 \(n\) 的,由 \(0\)\(9\) 构成的字符串 \(S\).
字符串中连续的一段被称为这个字符串的子串。如果一个字符串视为十进制数(可以有前导 \(0\) )时是 \(D\) 的倍数,就称它是一个倍数串。现在要把这个长为 \(n\) 的字符串切成若干段,也就是若干个首尾相连的子串。要求,切分后任意一对相邻的子串中至少有一个子串是倍数串;切分后的总段数小于 \(2\) 也可以。
问有多少种切分方案满足条件,答案对 \(10^9+7\) 取模。

题解

image

std

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
char s[100005];
int n,d,p,D,hsh[100005],cnt2,cnt5,t;
int f1[100005],f2[100005],sm1[1000005],sm2[1000005];
void work(){
	scanf("%s%d",s+1,&d);n=strlen(s+1);cnt2=cnt5=0;D=d;p=1;
	while(d%2==0)d/=2,p*=2,cnt2++;while(d%5==0)d/=5,p*=5,cnt5++;t=max(cnt2,cnt5);
	for(int i=n,pw=1;i>0;i--,pw=pw*10%d)hsh[i]=(hsh[i+1]+(s[i]-'0')*pw)%d;
	f1[0]=1;f2[0]=0;sm1[hsh[1]]=!t;
	for(int i=1,sum=1;i<=n;i++){
		f2[i]=sum;
		int v=0;
		for(int j=0,pw=1;j<i&&j<t;j++,pw=10*pw%D){
			v=(v+pw*(s[i-j]-'0'))%D;
			if(!v){
				f1[i]=(f1[i]+f2[i-j-1])%mod;
				f1[i]=(f1[i]+f1[i-j-1])%mod;
				f2[i]=(f2[i]+mod-f1[i-j-1])%mod;
			}
		}
		if(v%p==0){
			f1[i]=(f1[i]+sm2[hsh[i+1]])%mod;
			f1[i]=(f1[i]+sm1[hsh[i+1]])%mod;
			f2[i]=(f2[i]+mod-sm1[hsh[i+1]])%mod;
		}
		sum=(sum+f1[i])%mod;
		if(i>=t){
			sm1[hsh[i-t+1]]=(sm1[hsh[i-t+1]]+f1[i-t])%mod;
			sm2[hsh[i-t+1]]=(sm2[hsh[i-t+1]]+f2[i-t])%mod;
		}
	}
	printf("%d\n",(f1[n]+f2[n])%mod);
	for(int i=1;i<=n+1;i++)sm1[hsh[i]]=sm2[hsh[i]]=0,hsh[i]=f1[i]=f2[i]=0;
}
int main(){
	freopen("digit.in","r",stdin);
	freopen("digit.out","w",stdout);
	int tasd;
	for(scanf("%d",&tasd),1;tasd--;)work();
}

反思

考场想了想,感觉是 $ dp $ 一类的东西,但是由于我 \(dp\) 水平奇差无比,直接逃跑。

T2 乘法

题面

image

题解

image

反思

个人认为这个做法狗屁不通,至少他给的 \(std\) 里边我没看出来折半搜索。
考场上推出来个邪门的做法:
我们记在 \(B\) 进制下,最大的各个位数互不相同的数在十进制下表示为 \(k\)。这时求得倍数,从最大的倍数开始枚举,并判断是否是特殊的。
那么这玩意问题在哪呢?\(n\) 比较大时这个问题完全可以,我们就可以考虑 \(n\) 比较小时打全排列,个人猜测分界线大概定到 \(150\) 左右就差不多。
ps: \(c++\) 中提供了 \(prev\)_\(permutation(a.begin(),a.end())\) 上一个排列的函数。枚举更加方便

std

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int B=13;
ll gcd(ll x,ll y){ return x?gcd(y%x,x):y; }
ll pb[B];
bool leading_zero_needed=0;
ll n;int b;

namespace subt_small_n{

bool first;
bool u[B];
void ss(ll x,int y,bool lz){
	if(y==b){
		if(x%n==0){
			if(first){
				cout<<x;
				exit(0);
			}else first=1;
		}
		return;
	}
	if(leading_zero_needed&&y==0){
		ss(0,1,1);
	}else{
		for(int i=b-1;i>=0;--i){
			if(!u[i]){
				if(i||!lz)u[i]=1;
				ss(x+i*pb[b-y-1],y+1,lz&&!i);
				u[i]=0;
			}
		}
	}
}

}//namespace subt_small_n

namespace subt_large_n{

bool first;
void ss(ll x,int y,bool lz,int u){
//	if(x==0)cerr<<"> "<<x<<" "<<y<<" "<<lz<<endl;
	if(y==b-5&&n>pb[5]&&(x+n-1)/n*n-x>=pb[5])return;
	if(y==b-4&&n>pb[4]&&(x+n-1)/n*n-x>=pb[4])return;
//	if(x==2625)cerr<<"! "<<x<<" "<<y<<" "<<lz<<"  "<<u<<endl; 
	if(y==b-3){
		ll z=(x+n-1)/n*n-x;
		if(z>=b*b*b)return;
		ll a[3]={z/b/b,z/b%b,z%b};
//		cerr<<"a "<<a[0]<<" "<<a[1]<<" "<<a[2]<<"  "<<!((u>>a[0])&1)<<" "<<!((u>>a[1])&1)<<" "<<!((u>>a[2])&1)<<" "<<endl;
		if(a[1]&&a[1]==a[2])return;
		if((a[0]||!lz)&&(a[1]==a[2]||a[2]==a[0]||a[0]==a[1]))return;
		if((a[0]||!lz)&&!((u>>a[0])&1))return;
		if((a[0]||a[1]||!lz)&&!((u>>a[1])&1))return;
		if((a[0]||a[1]||a[2]||!lz)&&!((u>>a[2])&1))return;
		if(first){
			cout<<x+z;
			exit(0);
		}else first=1;
		return;
	}
	if(leading_zero_needed&&y==0){
		ss(0,1,1,(1<<b)-1);
	}else{
		int uu=u;
		for(;u;){
			int i=31-__builtin_clz(u);
			ss(x+i*pb[b-y-1],y+1,lz&&!i,uu^((i||!lz)<<i));
			u^=1<<i;
		}
	}
}

}

int main(){
	freopen("multi.in","r",stdin);
	freopen("multi.out","w",stdout);
	cin>>n>>b;
	int g=gcd(n,b-1);
	int s=b*(b-1)/2;
	if(s%g)leading_zero_needed=1;
	if(n%(b*b)==0)return cout<<"-1"<<endl,0;
	for(int i=pb[0]=1;i<=b;i++)pb[i]=pb[i-1]*b;
	if(n<=b*b*b||b<=4){
		subt_small_n::ss(0,0,1);
		cout<<"-1"<<endl;
	}else{
		subt_large_n::ss(0,0,1,(1<<b)-1);
		cout<<"-1"<<endl;
	}
	exit(0);
}

个人做法

#include<bits/stdc++.h>
#define io cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define ll long long
#define ri register int
#define lb long double


using namespace std;
using namespace __gnu_cxx;
const ll N =114514;
const ll mod=1e9+7;
ll a[13];

inline ll qp(ll x,ll b)
{
	ll res=1;
	while(b)
	{
		if(b&1) res=res*x;
		x=x*x;
		b>>=1;
	}
	return res;
}
inline ll change(ll a[],ll b)
{
	ll tmp=0;
	for(ri i=1; i<=b; i++)
	{
		tmp+=a[i]*pow(b,b-i);
	}
	return tmp;
}
ll n,b;
bool vis[13];
inline bool check(ll x)
{
	memset(vis,0,sizeof(vis));
	while(x)
	{
		if(vis[x%b])
			return false;
		vis[x%b]=true;
		x/=b;
	}
	return true;
}

int main()
{
	io;
	freopen("multi.in","r",stdin);
	freopen("multi.out","w",stdout);
	cin>>n>>b;
	for(ri i=0; i<b; i++)
		a[i+1]=i;
	reverse(a+1,a+1+b);
	ll maxs=change(a,b),tmp=0,tep=maxs/n+1,ans=0;
	for(ri i=tep; i>=0; i--)
	{
		if(check(i*n))
			tmp++,ans=i*n;
		if(tmp==2)
		{
			cout<<ans<<"\n";
			exit(0);
		}
	}
	cout<<-1<<"\n";
	return 0;
}
//这份代码考场挂了1个点,没有对n进行分类处理

T3 循环

题面

image

题解

image
感觉是错的因为和标程没半毛钱关系

std

#include <bits/stdc++.h>
using namespace std;
template <typename T> void read(T &t) {
	t=0; char ch=getchar(); int f=1;
	while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
	do { (t*=10)+=ch-'0'; ch=getchar(); } while ('0'<=ch&&ch<='9'); t*=f;
}
const int N=500010,M=100010;
typedef long long ll;
typedef unsigned long long ull;
mt19937_64 rnd(time(0));
int n,m,V,a[100010],b[100010],c[500010];
ll state;

int e[N];
ull f[N];
int l[N],r[N];

unordered_map<ull,ll>v;

int main() {
    freopen("cycle.in","r",stdin);
    freopen("cycle.out","w",stdout);
	read(n),read(m),read(V),read(state);
	ll sum=0;
	for (int i=0;i<n;i++) {
		state=(state*1103515245+12345)%(1LL<<31);
		c[i]=1+((state/10)%V);
		sum+=c[i];
		cerr<<c[i]<<' ';
	}
	cerr<<endl;
	for (int i=1;i<=m;i++) {
		state=(state*1103515245+12345)%(1LL<<31);
		a[i]=((state/10)%n);
		state=(state*1103515245+12345)%(1LL<<31);
		b[i]=((state/10)%n);
		cerr<<a[i]<<' '<<b[i]<<endl;
	}
	
	for(int i=1;i<=m;i++)if(a[i]>b[i])swap(a[i],b[i]);
	for(int i=1;i<=m;i++)e[a[i]]++,e[b[i]]--;
	for(int i=1;i<=m;i++){
		ull u=rnd();
		f[a[i]]^=u; f[b[i]]^=u;
	}
	ll ans=0;
	for(int i=0,t=0;i<n-1;i++){
		t+=e[i];
		if(t)ans+=c[i];
	}
	
	ull t=0;
	for(int i=0;i<n-1;i++){
		t^=f[i];
		v[t]+=c[i];
	}
	
	for(auto i:v)ans=min(ans,sum-i.second);
	cout<<ans<<endl;
	return 0;
}

T4 轰炸

题面

image

题解

image

std

#include <bits/stdc++.h>
using namespace std;
inline int read(){
	int s=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
	return s*f;
}
const int N=1e5+5,inf=1e9;
#define int long long
int prod=0;
const int mod=2.5e9+1;
inline int quick_pow(int a,int b){
	int ret=1;for(;b;b>>=1,a=a*a%mod)if(b&1)ret=ret*a%mod;
	return ret;
}
inline void Min(int &a,int b){if(a>b)a=b;}
int T,n,m,k;
int sum[N],d[2][N],bucx[N],bucy[N],lshy[N];
struct Node{int x,y;}a[N];
signed main(){
    freopen("cannon.in","r",stdin);
    freopen("cannon.out","w",stdout);
	T=read();
	while(T--){
		n=read(),m=read();k=read();
		memset(sum,0,(m+n)<<3);
		for(int i=1;i<=k;++i){
			a[i].x=read();a[i].y=read();
			bucx[i]=a[i].x;bucy[i]=a[i].y;
		}
		sort(bucx+1,bucx+1+k);
		int kx=unique(bucx+1,bucx+1+k)-bucx-1;
		sort(bucy+1,bucy+1+k);
		int ky=unique(bucy+1,bucy+1+k)-bucy-1;bucy[ky+1]=0;
		int cur=1,pre=0;
		for(int i=1,x;i<=kx;++i,cur^=1,pre^=1){
			memset(d[cur]+1,0x3f,m<<3);
			x=bucx[i];
			for(int j=1;j<=k;++j)
				Min(d[cur][a[j].y],abs(a[j].x-x));
			int r=1;
			d[cur][0]=inf;
			for(int j=ky-1;j>=1;--j)Min(d[cur][bucy[j]],d[cur][bucy[j+1]]+bucy[j+1]-bucy[j]);
			for(int j=1;j<=ky;++j){
				while(abs(bucy[j]-r)+d[cur][bucy[j]]<abs(bucy[j+1]-r)+d[cur][bucy[j+1]]&&r<=m){
					Min(d[cur][r],abs(bucy[j]-r)+d[cur][bucy[j]]);
					++r;
				}
			}
			if(i==1){
				for(int j=1;j<=m;++j){
					++sum[d[cur][j]];
					--sum[d[cur][j]+x];
				}
			}else{
				int b=bucx[i]+bucx[i-1];
				for(int j=1,p;j<=m;++j){
					p=(b+d[cur][j]-d[pre][j])>>1;
					++sum[d[pre][j]+1];
					--sum[d[pre][j]+p-bucx[i-1]+1];
					++sum[d[cur][j]];
					--sum[d[cur][j]+bucx[i]-p];
				}
			}
			if(i==kx&&x!=n){
				for(int j=1;j<=m;++j){
					++sum[d[cur][j]+1];
					--sum[d[cur][j]+n-x+1];
				}
			}
		}
		int inv=1,bs=n*m,ans=1,s=0,t=0;
		for(int i=0;i<n+m&&i<n*m;++i){
			inv=1ull*inv*(bs-i)%mod;
			s+=sum[i];t+=s;
			ans=1ull*ans*(t-i)%mod;
		}
		printf("%llu\n",1ull*quick_pow(inv,mod-2)*ans%mod);
	}
	return 0;
}

反思

开考后大概看了一遍题目,\(T1\)\(T4\) 一眼不会,直接逃跑,至少我现在看到计数类的问题就头大
\(T2\)读了两遍感觉可写,就直接开的 \(T2\),上来没啥思路,先打了个 $ \mathcal{O}( n!)$ 的全排列,出去转了一会发现不用这么搞,直接枚举倍数即刻,直接开写,稍微调了一会就出来了
\(T3\)没啥思路,又出去转一圈,想到一个 $ \mathcal{O}(2^p)$ 的做,回来看数据范围一分没有,于是随便打了个暴力逃跑。
个人认为还是太菜导致的,需要多看看 \(dp\).

posted @ 2024-11-13 20:09  warfarin  阅读(3)  评论(0编辑  收藏  举报