Day1
T1
题解
显然是一个撞鸭$DP$,考虑如何定义。
定义$dp[i][j][k]$表示处理到第$i$行,第$i$行的按钮状态为$j$,第$i$行的覆盖状态为$k$的最小代价。
为了方便计算,因为如果一个覆盖状态是当前覆盖状态的子集,也就是说我们可以用当前覆盖状态的代价制造出那个覆盖状态(可以重复覆盖),所以每次将其子集与其取$\min$即可。
时间复杂度:$\Theta(n\times 2^m\times 3^m)$。
代码时刻
#include<bits/stdc++.h>
using namespace std;
int n,m;
char ch[20];
int Map[20][20],state[20],v[20][1100],dp[20][1100][1100],f[1100];
int ans=0x3f3f3f3f;
int main()
{
memset(dp,0x3f,sizeof(dp));dp[0][0][0]=0;
scanf("%d%d",&n,&m);
state[0]=(1<<m)-1;
for(int i=1;i<=n;i++)
{
scanf("%s",ch+1);
for(int j=1;j<=m;j++)
if(ch[j]-'0')
state[i]|=1<<(j-1);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&Map[i][j]);
for(int i=1;i<=m;i++)Map[n+1][i]=0x3f3f3f3f;
for(int i=1;i<=n+1;i++)
for(int j=0;j<(1<<m);j++)
for(int k=1;k<=m;k++)
if(j&(1<<(k-1)))v[i][j]+=Map[i][k];
for(int i=0;i<(1<<m);i++)
{
f[i]=i;
for(int j=1;j<=m;j++)
if(i&(1<<(j-1)))
f[i]|=((1<<(j-2))|(1<<j));
}
for(int i=1;i<=n+1;i++)
{
for(int j=0;j<(1<<m);j++)
for(int k=0;k<(1<<m);k++)
dp[i][j][k|state[i]]=min(dp[i][j][k|state[i]],dp[i-1][k][(~((j|f[k]|state[i-1])&((1<<m)-1)))&((1<<m)-1)]+v[i][j]);
for(int j=0;j<(1<<m);j++)
for(int k=(1<<m)-1;k>=0;k--)
for(int l=k;l;l-=l&-l)
dp[i][j][k^(l&-l)]=min(dp[i][j][k^(l&-l)],dp[i][j][k]);
}
for(int i=0;i<(1<<m);i++)ans=min(ans,dp[n+1][0][i]);
printf("%d",ans);
return 0;
}
T2
题解
单独考虑第一问,答案其实就是将$val$排序后$\prod \limits_{i=1}^n\min(i,key_i)$,注意$val$可能相同,不妨设前面$sum$个都与其相同,那么答案就变成了
$$\prod\limits_{i=1}^n\min(i,key_i+sum)$$
再来考虑第二问的构造,问题可以转化为区间最值,线段书维护即可。
时间复杂度:$\Theta(n\log n)$。
代码时刻
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
const int mod=1000000007;
struct rec{int key,val;}e[500001];
map<int,int>mp;
int n;
int cnt;
long long ans=1;
deque<int>q[500001];
int mn[2000001],id[2000001],lz[2000001];
pair<int,int> tr[2000001];
bool cmp1(rec a,rec b){return a.val==b.val?a.key<b.key:a.val>b.val;}
bool cmp2(rec a,rec b){return a.val==b.val?a.key<b.key:a.val<b.val;}
void pushup(int x)
{
if(mn[L(x)]<=mn[R(x)]){mn[x]=mn[L(x)];id[x]=id[L(x)];}
else{mn[x]=mn[R(x)];id[x]=id[R(x)];}
tr[x]=min(tr[L(x)],tr[R(x)]);
}
void pushdown(int x)
{
mn[L(x)]-=lz[x];
mn[R(x)]-=lz[x];
lz[L(x)]+=lz[x];
lz[R(x)]+=lz[x];
lz[x]=0;
}
void add1(int x,int l,int r,int k,int w)
{
if(l==r)
{
q[l].push_back(w);
if(q[l].size()==1)
{
mn[x]=e[q[l].front()].key;
tr[x]=make_pair(e[q[l].front()].key,e[q[l].front()].val);
id[x]=l;
}
return;
}
int mid=(l+r)>>1;
if(k<=mid)add1(L(x),l,mid,k,w);
else add1(R(x),mid+1,r,k,w);
pushup(x);
}
void add2(int x,int l,int r,int L,int R)
{
if(L>R)return;
if(r<L||R<l)return;
if(L<=l&&r<=R)
{
mn[x]--;
lz[x]++;
return;
}
pushdown(x);
int mid=(l+r)>>1;
add2(L(x),l,mid,L,R);
add2(R(x),mid+1,r,L,R);
pushup(x);
}
void del(int x,int l,int r,int k)
{
if(l==r)
{
q[l].pop_front();
if(q[l].size()&&q[l].front())
{
mn[x]=e[q[l].front()].key-lz[x];
tr[x]=make_pair(e[q[l].front()].key,e[q[l].front()].val);
id[x]=l;
}
else
{
mn[x]=0x3f3f3f3f;
tr[x]=make_pair(0x3f3f3f3f,0x3f3f3f3f);
id[x]=l;
}
return;
}
pushdown(x);
int mid=(l+r)>>1;
if(k<=mid)del(L(x),l,mid,k);
else del(R(x),mid+1,r,k);
pushup(x);
}
pair<int,int> ask(int x,int l,int r,int L,int R)
{
if(r<L||R<l)return make_pair(0x3f3f3f3f,0x3f3f3f3f);
if(L<=l&&r<=R)return tr[x];
pushdown(x);
int mid=(l+r)>>1;
return min(ask(L(x),l,mid,L,R),ask(R(x),mid+1,r,L,R));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&e[i].key,&e[i].val);
sort(e+1,e+n+1,cmp1);
int sum=0;
for(int i=1;i<=n;i++)
{
if(e[i].val==e[i-1].val)sum++;
else sum=0;
ans=ans*min(i,e[i].key+sum)%mod;
}
printf("%lld\n",ans);
sort(e+1,e+n+1,cmp2);
int lst=-1;
for(int i=1;i<=n;i++)
{
if(e[i].val!=lst)
{
lst=e[i].val;
mp[e[i].val]=++cnt;
}
}
for(int i=1;i<=n;i++)
add1(1,1,cnt,mp[e[i].val],i);
for(int i=1;i<=n;i++)
{
int res;
if(mn[1]==1)res=id[1];
else res=cnt;
pair<int,int> flag=ask(1,1,cnt,1,res);
printf("%d %d\n",flag.first,flag.second);
del(1,1,cnt,mp[flag.second]);
add2(1,1,cnt,1,mp[flag.second]-1);
}
return 0;
}
T3
题解
先来考虑确定了所有边权之后如何判定,无非就是当$dis(1\sim i)+dis(i\sim n)=dis(1\sim n)$。
好吧我没打正解……
枚举所有本来就有的边的边权即可,不要忘了$0$和$inf$。
时间复杂度:$\Theta(n\times m\times \log n)$。
代码时刻
#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to,w;}e[5000];
int head[1001],cnt;
int n,m;
long long disf[1001],disr[1001];
bool vis[1001];
long long que[2001];
bool ans[1001];
priority_queue<pair<long long,int>,vector<pair<long long,int>>,greater<pair<long long,int>>>q;
void add(int x,int y,int w)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].w=w;
head[x]=cnt;
}
void Dijf(int w)
{
memset(disf,0x3f,sizeof(disf));
memset(vis,0,sizeof(vis));
q.push(make_pair(0,1));
disf[1]=0;
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis[x])continue;
vis[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
if(disf[e[i].to]>disf[x]+(e[i].w==-1?w:e[i].w))
{
disf[e[i].to]=disf[x]+(e[i].w==-1?w:e[i].w);
q.push(make_pair(disf[e[i].to],e[i].to));
}
}
}
}
void Dijr(int w)
{
memset(disr,0x3f,sizeof(disr));
memset(vis,0,sizeof(vis));
q.push(make_pair(0,n));
disr[n]=0;
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis[x])continue;
vis[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
if(disr[e[i].to]>disr[x]+(e[i].w==-1?w:e[i].w))
{
disr[e[i].to]=disr[x]+(e[i].w==-1?w:e[i].w);
q.push(make_pair(disr[e[i].to],e[i].to));
}
}
}
}
void judge(long long x)
{
Dijf(x);
Dijr(x);
for(int i=1;i<=n;i++)if(disf[i]+disr[i]==disf[n])ans[i]=1;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);add(v,u,w);
if(w!=-1)que[++que[0]]=w;
}
que[++que[0]]=0;que[++que[0]]=0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=que[0];i++)
judge(que[i]);
for(int i=1;i<=n;i++)printf("%d",ans[i]);
return 0;
}
Day2
T1
题解
找规律发现其实就是$\frac{n^2-1}{9}$。
时间复杂度:$\Theta(T)$。
代码时刻
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
const int qpw=443664157;
long long n;
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);n%=mod;
printf("%lld\n",(n*n%mod-1)*qpw%mod);
}
return 0;
}
T2
又没有打正解……
建两棵$Trie$树,一正一反,将每一个字符串都扔进$Trie$树里,对于$Trie$树上的每一个点记录如下信息:
$\alpha.$前缀$hash$值。
$\beta.$深度。
$\gamma.$前缀节点个数。
将相同深度的节点信息压如一个$vector$即可。
然后枚举字串的中点,即后缀和前缀的分界点,然后在左右分别二分最长可行前后缀,$judge$的时候在当前长度(深度)的$vector$里查找有没有$hash$值相同的即可。
比正解多一个$\log$,但是常数较小,跑的甚至比正解快(也可以用$hash\text{_}map$剪掉这个$\log$)。
时间复杂度:$\Theta(n\log^2n)$。
代码时刻
#include<bits/stdc++.h>
using namespace std;
int m,lenS;
char s[200001],str[200001];
int cnt[]={1,1},trie[2][200001][30];
unsigned long long ed[2][200001];
unsigned long long mod[200001];
unsigned long long S[200001];
vector<pair<unsigned long long,int>> vec[2][200001];
long long ans;
void insertf(char *str)
{
int len=strlen(str+1),p=1;
for(int k=1;k<=len;k++)
{
int ch=str[k]-'a';
if(!trie[0][p][ch])
trie[0][p][ch]=++cnt[0];
p=trie[0][p][ch];
ed[0][p]++;
}
}
void insertr(char *str)
{
int len=strlen(str+1),p=1;
for(int k=len;k;k--)
{
int ch=str[k]-'a';
if(!trie[1][p][ch])
trie[1][p][ch]=++cnt[1];
p=trie[1][p][ch];
ed[1][p]++;
}
}
void dfsf(int x,int d,unsigned long long hash)
{
for(int i=0;i<26;i++)
if(trie[0][x][i])
{
ed[0][trie[0][x][i]]+=ed[0][x];
vec[0][d+1].push_back(make_pair(hash*131+i+1,ed[0][trie[0][x][i]]));
dfsf(trie[0][x][i],d+1,hash*131+i+1);
}
}
void dfsr(int x,int d,unsigned long long hash)
{
for(int i=0;i<26;i++)
if(trie[1][x][i])
{
ed[1][trie[1][x][i]]+=ed[1][x];
vec[1][d+1].push_back(make_pair(hash+mod[d]*(i+1),ed[1][trie[1][x][i]]));
dfsr(trie[1][x][i],d+1,hash+mod[d]*(i+1));
}
}
long long judgef(int mid,int x)
{
if(!vec[0][mid].size())return 0;
pair<unsigned long long,int> w=make_pair(S[x+mid-1]-S[x-1]*mod[mid],0);
int flag=lower_bound(vec[0][mid].begin(),vec[0][mid].end(),w)-vec[0][mid].begin();
if(vec[0][mid][flag].first==S[x+mid-1]-S[x-1]*mod[mid])return vec[0][mid][flag].second;
return 0;
}
long long judger(int mid,int x)
{
if(!vec[1][mid].size())return 0;
pair<unsigned long long,int> w=make_pair(S[x]-S[x-mid]*mod[mid],0);
int flag=lower_bound(vec[1][mid].begin(),vec[1][mid].end(),w)-vec[1][mid].begin();
if(vec[1][mid][flag].first==S[x]-S[x-mid]*mod[mid])return vec[1][mid][flag].second;
return 0;
}
long long findf(int x)
{
int lft=1,rht=lenS-x+1;
long long res=0;
while(lft<=rht)
{
int mid=(lft+rht)>>1;
long long flag=judgef(mid,x);
if(flag){res=flag;lft=mid+1;}
else rht=mid-1;
}
return res;
}
long long findr(int x)
{
int lft=1,rht=x;
long long res=0;
while(lft<=rht)
{
int mid=(lft+rht)>>1;
long long flag=judger(mid,x);
if(flag){res=flag;lft=mid+1;}
else rht=mid-1;
}
return res;
}
int main()
{
mod[0]=1;for(int i=1;i<=200000;i++)mod[i]=mod[i-1]*131;
scanf("%s%d",str+1,&m);
lenS=strlen(str+1);
for(int i=1;i<=lenS;i++)S[i]=S[i-1]*131+str[i]-'a'+1;
for(int i=1;i<=m;i++)
{
scanf("%s",s+1);
insertf(s);
insertr(s);
}
dfsf(1,0,0);
dfsr(1,0,0);
for(int i=1;i<=200000;i++)
{
if(vec[0][i].size())sort(vec[0][i].begin(),vec[0][i].end());
if(vec[1][i].size())sort(vec[1][i].begin(),vec[1][i].end());
}
for(int i=1;i<lenS;i++)
ans+=findr(i)*findf(i+1);
printf("%lld",ans);
return 0;
}
T3
题解
需要分类讨论。
注意不要炸$long\ long$即可。
时间复杂度:$\Theta(\log_{mod}n)$。
代码时刻
#include<bits/stdc++.h>
using namespace std;
const int mod=300007;
long long n,m,k;
long long fac[mod],inv[mod];
long long ans;
long long qpow(long long x,long long y)
{
long long res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
void pre_work()
{
fac[0]=1;
for(int i=1;i<mod;i++)fac[i]=fac[i-1]*i%mod;
inv[mod-1]=qpow(fac[mod-1],mod-2);
for(int i=mod-1;i;i--)inv[i-1]=inv[i]*i%mod;
}
long long lucas(long long x,long long y)
{
if(x<y)return 0;
return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
long long C(long long x,long long y)
{
if(x<y)return 0;
if(!y)return 1;
return lucas(x%mod,y%mod)*C(x/mod,y/mod)%mod;
}
long long get1(long long x){return (2*x%mod*x%mod*x%mod+3*x%mod*x%mod+x)%mod*qpow(6,mod-2)%mod;}
long long get2(long long x){return (x*(x+1))>>1;}
long long work0(){return((C(n,k)*(m%mod)%mod+C(m,k)*(n%mod)%mod)%mod+2*C(m+1,k+1)+2*C(m,k)*((n-m)%mod)%mod+2*C(m,k+1)%mod)%mod;}
long long work1(){return n%mod*(m%mod)%mod;}
void work2(){}
long long work3()
{
long long X=(min(n+1,(m+2)>>1)-1)%mod;
long long Y=(min(m+1,(n+2)>>1)-1)%mod;
n%=mod;m%=mod;
return (2*(n*m%mod*(X+Y)%mod+2*(get1(X)+get1(Y))%mod-(2*n+m)*get2(X)%mod-(2*m+n)*get2(Y)%mod+mod)%mod+4*(n*m%mod*(m-1)%mod+get1(m-1)-(n+m)*get2(m-1)%mod+mod)%mod+mod)%mod;
}
long long work4()
{
long long X=(min(n+1,(m+2)>>1)-1)%mod;
long long Y=(min(m+1,(n+2)>>1)-1)%mod;
long long Z=(m>>1)%mod;n%=mod;m%=mod;
return (2*(n*m%mod*(X+Y)%mod+2*(get1(X)+get1(Y))%mod-(2*n+m)*get2(X)%mod-(2*m+n)*get2(Y)%mod+mod)%mod+(n*m%mod*(m-1)%mod+get1(m-1)-(n+m)*get2(m-1)%mod+mod)%mod+5*(n*m%mod*Z%mod-2*(n+m)*get2(Z)%mod+4*get1(Z)+mod)%mod+mod)%mod;
}
long long work5()
{
long long X=((m-1)>>1)%mod;
n%=mod;m%=mod;
return (2*n*m%mod*X%mod+8*get1(X)%mod-4*(n+m)%mod*get2(X)%mod+mod)%mod;
}
void work6(){}
int main()
{
pre_work();
int T;scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&m,&k);
if(n<m)n^=m^=n^=m;
if(k>1)ans=work0();
switch(k)
{
case 1:ans=work1();break;
case 2:work2();break;
case 3:ans=(ans+work3())%mod;break;
case 4:ans=(ans+work4())%mod;break;
case 5:ans=(ans+work5())%mod;break;
default:work6();
}
printf("%lld\n",ans);
}
return 0;
}
最后声明:此博客中涉及的试题题面高度保密,请勿滥用此博客