11.13考后反思
T1 数位
题面
有一个正整数 \(D\) 和一个长为 \(n\) 的,由 \(0\) 到 \(9\) 构成的字符串 \(S\).
字符串中连续的一段被称为这个字符串的子串。如果一个字符串视为十进制数(可以有前导 \(0\) )时是 \(D\) 的倍数,就称它是一个倍数串。现在要把这个长为 \(n\) 的字符串切成若干段,也就是若干个首尾相连的子串。要求,切分后任意一对相邻的子串中至少有一个子串是倍数串;切分后的总段数小于 \(2\) 也可以。
问有多少种切分方案满足条件,答案对 \(10^9+7\) 取模。
题解
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 乘法
题面
题解
反思
个人认为这个做法狗屁不通,至少他给的 \(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 循环
题面
题解
感觉是错的因为和标程没半毛钱关系
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 轰炸
题面
题解
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\).