D-Kefa and Dishes
感觉最近几天遇到了好几次这个类型的题:其实本质上都是TSP问题吧,状压记录一下状态之后第二维维护最后一个被吃的食物。那么转移就很显然有dp[m][k]=max(dp[m][k],dp[i][j]+w[k]+mp[j][k])。最后找到所有1的个数为m状态就好了,用__builtin_popcount()这个函数比较方便。
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=20;
ll dp[1<<N][N],a[N],mp[N][N];
int main() {
int n,m,k;
ll ans=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=k;i++) {
int u,v,w;
scanf("%d%d%lld",&u,&v,&w);
mp[u][v]=w;
}
for(int i=1;i<=n;i++) dp[1<<(i-1)][i]=a[i];
for(int i=1;i<=(1<<n)-1;i++)
for(int j=1;j<=n;j++) {
if(i&(1<<(j-1))) {
for(int k=1;k<=n;k++) {
if(!(i&(1<<(k-1)))) {
int m=i|(1<<(k-1));
dp[m][k]=max(dp[m][k],dp[i][j]+a[k]+mp[j][k]);
}
}
}
}
for(int i=1;i<=(1<<n)-1;i++)
if(__builtin_popcount(i)==m) {
for(int j=1;j<=n;j++) {
if(i&(1<<(j-1))) ans=max(ans,dp[i][j]);
}
}
printf("%lld\n",ans);
return 0;
}
E-Kefa and Watch
这道题是给定一个数字串,然后要求支持两个操作:1.查询某个区间里面的串是否是满足周期为d的一个字符串 2.修改某一段区间的字符串为c,这里c确保了是一个数字。然后这个区间操作就直接联想到了线段树。但是如何用线段树来维护字符串的信息,这里就要用到哈希。字符串的哈希值用线段树维护只要注意到1. pushup的时候相当于就是把两个字符串拼接在一起,让前面的字符串换算一下就好了。2.modify的时候因为是同一个数的字符串,这个只要预处理一下哈希就好了。3.区间查询的时候因为我们是知道右边界的位置的,所有把每一段都分别换算进去就好了。4.查询一个串是不是周期为d的字符串,只要判断[l,r-d]和[l+d,r]字符串是不是相等的就好了(这个思路比较关键)写起来不是很好写,这个题目也可以加入线段树教做人系列了。
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+50;
const ull h1=131,h2=233,mod=1e9+7;
ull qow1[N],qow2[N],H1[10][N],H2[10][N];
char s[N];
int lazy[N];
struct node{
ull sum1,sum2;
int l,r;
}tr[N<<2];
void pushup(int rt) {
int len=tr[rt<<1|1].r-tr[rt<<1|1].l+1;
tr[rt].sum1=tr[rt<<1].sum1*qow1[len]+tr[rt<<1|1].sum1,tr[rt].sum1%=mod;
tr[rt].sum2=tr[rt<<1].sum2*qow2[len]+tr[rt<<1|1].sum2,tr[rt].sum2%=mod;
}
void build(int rt,int l,int r) {
tr[rt].l=l,tr[rt].r=r,lazy[rt]=-1;
if(l==r) { tr[rt].sum1=tr[rt].sum2=s[l]-'0';return; }
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void pushdown(int rt) {
if(lazy[rt]!=-1) {
lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
tr[rt<<1].sum1=H1[lazy[rt]][tr[rt<<1].r-tr[rt<<1].l+1];
tr[rt<<1].sum2=H2[lazy[rt]][tr[rt<<1].r-tr[rt<<1].l+1];
tr[rt<<1|1].sum1=H1[lazy[rt]][tr[rt<<1|1].r-tr[rt<<1|1].l+1];
tr[rt<<1|1].sum2=H2[lazy[rt]][tr[rt<<1|1].r-tr[rt<<1|1].l+1];
lazy[rt]=-1;
}
}
void modify(int rt,int l,int r,int L,int R,int val) {
if(R<l||L>r) return;
if(L<=l&&r<=R) {
tr[rt].sum1=H1[val][tr[rt].r-tr[rt].l+1];
tr[rt].sum2=H2[val][tr[rt].r-tr[rt].l+1];
lazy[rt]=val;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
modify(rt<<1,l,mid,L,R,val);
modify(rt<<1|1,mid+1,r,L,R,val);
pushup(rt);
}
void query(int rt,int l,int r,int L,int R,ull &tmp1,ull &tmp2) {
if(L<=l&&r<=R) {
tmp1=(tmp1+tr[rt].sum1*qow1[R-r])%mod;
tmp2=(tmp2+tr[rt].sum2*qow2[R-r])%mod;
return;
}
else {
int mid=(l+r)>>1;
pushdown(rt);
if(L<=mid) query(rt<<1,l,mid,L,R,tmp1,tmp2);
if(R>mid) query(rt<<1|1,mid+1,r,L,R,tmp1,tmp2);
}
}
void unit() {
qow1[0]=qow2[0]=1;
for(int i=1;i<=(int)1e5;i++) {
qow1[i]=qow1[i-1]*h1,qow1[i]%=mod;
qow2[i]=qow2[i-1]*h2,qow2[i]%=mod;
}
for(int i=0;i<=9;i++) {
for(int j=1;j<=(int)1e5;j++) {
H1[i][j]=H1[i][j-1]*h1+i,H1[i][j]%=mod;
H2[i][j]=H2[i][j-1]*h2+i,H2[i][j]%=mod;
}
}
}
int main() {
unit();
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
scanf("%s",s+1),q+=m;
build(1,1,n);
while(q--) {
int opt,l,r,d;
scanf("%d%d%d%d",&opt,&l,&r,&d);
if(opt==1) { modify(1,1,n,l,r,d); }
if(opt==2) {
if(r-l+1==d) { puts("YES");continue; }
ull ans11=0,ans12=0;
query(1,1,n,l+d,r,ans11,ans12);
ull ans21=0,ans22=0;
query(1,1,n,l,r-d,ans21,ans22);
if( ans11==ans21 && ans12==ans22 ) puts("YES");
else puts("NO");
}
}
return 0;
}