T1 出了个大阴间题
解题思路
看了看数据,大概是个状压 DP,但是感觉记忆化搜索比较好写一点(然而并不是这样递归比迭代常熟大了许多。。)
不难判断出来 b 的数值与合并的顺序无关于是我们可以预先处理来,最大值也是可以直接求的,从大到小合并。
DP 记录一下已经选择的数字的状态,当前的 a 的方案数,总和以及是否可以达到最大值。
然后转移计算贡献就好了(真没啥好说的)
code
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=25,mod=1e9+7;
int n,m,cnt,b[N],s[N];
ll ans,maxn,lsh[N*N];
struct Node{int dat,all;bool can;}f[150][1ll<<18];
int Pre_work()
{
sort(s+1,s+n+1);
int a=s[1];
for(int i=2;i<=n;i++)
a=(a==s[i])?a+1:max(a,s[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
lsh[++cnt]=s[i]+j-1;
sort(lsh+1,lsh+cnt+1); cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
return a;
}
void clear()
{
for(int i=1;i<=cnt;i++)
for(int j=0;j<(1<<n);j++)
f[i][j].dat=-1;
}
Node dfs(int x,int sta,int a)
{
int pos=lower_bound(lsh+1,lsh+cnt+1,a)-lsh;
if(~f[pos][sta].dat) return f[pos][sta];
if(x==n) return f[pos][sta]=(Node){0,1,a==maxn};
int res=0,tot=0; bool can=false;
for(int i=1;i<=n;i++)
{
if((sta>>i-1)&1) continue;
int na=(a==s[i])?a+1:max(a,s[i]);
int p=lower_bound(lsh+1,lsh+cnt+1,na)-lsh;
Node temp=dfs(x+1,sta|(1ll<<i-1),na);
if(!temp.can) continue; can=true;
tot=(1ll*tot+temp.all)%mod;
res=(res+1ll*(1ll*m*na%mod+b[x-1])*temp.all+temp.dat)%mod;
}
return f[pos][sta]=(Node){res,tot,can};
}
signed main()
{
freopen("repair.in","r",stdin); freopen("repair.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;i++) s[i]=read(),b[i]=b[i-1]*2+1;
maxn=Pre_work();
for(int i=1;i<=n;i++)
{
clear();
Node temp=dfs(1,1ll<<i-1,s[i]);
if(temp.can) ans=(ans+temp.dat)%mod;
}
printf("%lld %lld",maxn,ans);
return 0;
}
T2 最简单辣快来做
解题思路
发现 n 的范围比较小,我们可以对于每个卫星的坐标离散化一下,维护四个方向(区域)的和。
然后计算询问的时候分别查询在所有卫星中距离最近的两个横坐标两个纵坐标。
对于四个区域的答案分别将剩余的在离散化数组间隙中的计算进去。
光速幂可以快速的求出 a 或者 b 的次方,省掉一个 log
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=4e3+10,M=1e5+10,base=1e5;
int n,q,mod,w,h,a,b,pre[N][N][4];//0->left,up; 1->right,up; 2->left,down; 3->right,down
int cnt1,cnt2,val[N][N],lsh1[N<<1],lsh2[N<<1],pa1[M],pa2[M],pb1[M],pb2[M];
struct Node{int h,x,y;}s[N];
int power(int x,int y,int p=mod)
{
if(y<0) return 0;
if(x==a) return pa1[y/base]*pa2[y%base]%mod;
return pb1[y/base]*pb2[y%base]%mod;
}
int solve()
{
int x,y,ans=0; x=read(); y=read();
int posx=upper_bound(lsh1+1,lsh1+cnt1+1,x)-lsh1-1;
int posy=upper_bound(lsh2+1,lsh2+cnt2+1,y)-lsh2-1;
if(posx&&posy) ans=(ans+pre[posx][posy][0]*power(a,x-lsh1[posx])%mod*power(b,y-lsh2[posy])%mod)%mod;
if(posx&&posy<cnt2) ans=(ans+pre[posx][posy+1][1]*power(a,x-lsh1[posx])%mod*power(b,lsh2[posy+1]-y)%mod)%mod;
if(posx<cnt1&&posy) ans=(ans+pre[posx+1][posy][2]*power(a,lsh1[posx+1]-x)%mod*power(b,y-lsh2[posy])%mod)%mod;
if(posx<cnt1&&posy<cnt2) ans=(ans+pre[posx+1][posy+1][3]*power(a,lsh1[posx+1]-x)%mod*power(b,lsh2[posy+1]-y)%mod)%mod;
return ans;
}
signed main()
{
freopen("satellite.in","r",stdin); freopen("satellite.out","w",stdout);
n=read(); q=read(); w=read(); h=read(); mod=read(); a=read(); b=read(); pa1[0]=pa2[0]=pb1[0]=pb2[0]=1;
for(int i=1;i<=n;i++) s[i].h=read(),s[i].x=read(),s[i].y=read(),lsh1[++cnt1]=s[i].x,lsh2[++cnt2]=s[i].y;
sort(lsh1+1,lsh1+cnt1+1); cnt1=unique(lsh1+1,lsh1+cnt1+1)-lsh1-1;
sort(lsh2+1,lsh2+cnt2+1); cnt2=unique(lsh2+1,lsh2+cnt2+1)-lsh2-1;
for(int i=1;i<=base;i++) pa2[i]=pa2[i-1]*a%mod,pb2[i]=pb2[i-1]*b%mod;
for(int i=1;i<=base;i++) pa1[i]=pa1[i-1]*pa2[base]%mod,pb1[i]=pb1[i-1]*pb2[base]%mod;
for(int i=1;i<=n;i++)
s[i].x=lower_bound(lsh1+1,lsh1+cnt1+1,s[i].x)-lsh1,
s[i].y=lower_bound(lsh2+1,lsh2+cnt2+1,s[i].y)-lsh2,
val[s[i].x][s[i].y]=(val[s[i].x][s[i].y]+s[i].h)%mod;
for(int i=1;i<=cnt1;i++)
for(int j=1;j<=cnt2;j++)
{
int pa=power(a,lsh1[i]-lsh1[i-1]),pb=power(b,lsh2[j]-lsh2[j-1]);
pre[i][j][0]=(val[i][j]+pre[i-1][j][0]*pa%mod+pre[i][j-1][0]*pb%mod-pre[i-1][j-1][0]*pa%mod*pb%mod+mod)%mod;
}
for(int i=1;i<=cnt1;i++)
for(int j=cnt2;j>=1;j--)
{
int pa=power(a,lsh1[i]-lsh1[i-1]),pb=power(b,lsh2[j+1]-lsh2[j]);
pre[i][j][1]=(val[i][j]+pre[i-1][j][1]*pa%mod+pre[i][j+1][1]*pb%mod-pre[i-1][j+1][1]*pa%mod*pb%mod+mod)%mod;
}
for(int i=cnt1;i>=1;i--)
for(int j=1;j<=cnt2;j++)
{
int pa=power(a,lsh1[i+1]-lsh1[i]),pb=power(b,lsh2[j]-lsh2[j-1]);
pre[i][j][2]=(val[i][j]+pre[i+1][j][2]*pa%mod+pre[i][j-1][2]*pb%mod-pre[i+1][j-1][2]*pa%mod*pb%mod+mod)%mod;
}
for(int i=cnt1;i>=1;i--)
for(int j=cnt2;j>=1;j--)
{
int pa=power(a,lsh1[i+1]-lsh1[i]),pb=power(b,lsh2[j+1]-lsh2[j]);
pre[i][j][3]=(val[i][j]+pre[i+1][j][3]*pa%mod+pre[i][j+1][3]*pb%mod-pre[i+1][j+1][3]*pa%mod*pb%mod+mod)%mod;
}
while(q--) printf("%lld\n",solve());
return 0;
}
T3 是我的你不要抢
解题思路
直接 map 记忆化一下 Hash,对于每一个曾经有过的询问直接回答。
证明一下复杂度,假如串长都是 \(\le\sqrt{L}\) 那么 对于每一次询问的最大复杂度就是 \(\sqrt{L}\) 询问次数也就是 \(L\) 时间完全允许。
如果串长 \(\ge\sqrt{L}\) 询问最多也就有 \(L\) 个,证明类似于上面的。
code
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
using namespace __gnu_pbds;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=6e5+10,M=1e3+10;
const ull base=133331;
int n,m,q,l[N];
ull p[N];
string ch;
vector<string> v;
vector<ull> has[N];
gp_hash_table<int,int> mp[N];
int solve(int x,int y)
{
int lim=min(l[x],l[y]);
for(int len=lim;len;len--)
if(has[x][l[x]]-has[x][l[x]-len]*p[len]==has[y][len])
return len;
return 0;
}
signed main()
{
freopen("string.in","r",stdin); freopen("string.out","w",stdout);
n=read(); q=read(); v.push_back(ch); p[0]=1;
for(int i=1;i<=n;i++) cin>>ch,v.push_back(ch),l[i]=ch.size(),m=max(m,l[i]);
for(int i=1;i<=m;i++) p[i]=p[i-1]*base;
for(int i=1;i<=n;i++)
{
v[i]=" "+v[i]; has[i].push_back(0);
for(int j=1;j<=l[i];j++) has[i].push_back(has[i][j-1]*base+v[i][j]);
}
while(q--)
{
int x,y; x=read(); y=read();
if(mp[x].find(y)==mp[x].end()) mp[x].insert(make_pair(y,solve(x,y)));
printf("%lld\n",mp[x].find(y)->second);
}
return 0;
}
T4 显然也是我整的
解题思路
这个题。。。题解咋说就咋整就行了,别的就。。
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e5+10;
int n,m,T,top,sta[N],s[N];
set<int> se;
void work(int &ans,int &n)
{
int num=(*se.begin()),temp=2*num-n;
for(auto it=se.begin();it!=se.end();it++) sta[++top]=(*it);
ans+=temp; n-=temp; se.clear();
for(int i=1;i<=top;i++) se.insert(sta[i]-temp);
}
int solve(int n)
{
int ans=top=0,gcd=0;
if((*se.begin())>n/2) work(ans,n);
for(auto it=se.begin();it!=se.end();it++)
if((*it)<=n/2) gcd=__gcd(gcd,(*it));
else break;
se.erase(se.begin(),se.upper_bound(n/2));
for(auto it=se.begin();it!=se.end();it++)
if((*it)+gcd<=n) gcd=__gcd(gcd,(*it));
else break;
se.erase(se.begin(),se.upper_bound(n-gcd));
if(!se.size()) return ans+gcd;
int temp=gcd+n%gcd; top=0;
for(auto it=se.begin();it!=se.end();it++) sta[++top]=(*it);
se.clear(); for(int i=1;i<=top;i++) se.insert(temp+sta[i]-n); se.insert(gcd);
return ans+solve(temp);
}
signed main()
{
freopen("graph.in","r",stdin); freopen("graph.out","w",stdout);
T=read();
while(T--)
{
n=read(); m=read(); se.clear();
for(int i=1;i<=m;i++) s[i]=read();
for(int i=1;i<=m;i++) se.insert(s[i]);
printf("%lld\n",solve(n));
}
return 0;
}