感觉离散课上都讲过。。k很小,,由于 ai=ai−1∗10+xmodk 。所以在这样的完全由数字x构成的序列,必然在前k+1次进入循环。我们只要暴力找出这个循环就行了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
typedef long long LL;
int cas;
LL x,m,k,c;
int way[11000];
int pp[11000];
int tail,ini;
int main()
{
int T;
cin>>T;
while (T--)
{
cin>>x>>m>>k>>c;
printf("Case #%d:\n",++cas);
memset(pp,-1,sizeof(pp));
tail=0;
LL now=0;
for (int i=0;;i++)
{
now=now*10+x;
now%=k;
if (pp[now]==-1)
{
pp[now]=i;
way[tail++]=now;
}
else
{
ini=pp[now];
break;
}
}
int begin=ini;
m--;
if (m<=ini)
{
if (way[m]==c) printf("Yes\n");
else printf("No\n");
}
else
{
m-=ini;
m%=(tail-ini);
if (way[m+ini]==c) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
n<16,所以我们可以状压dp搞一波,f[i][j]表示数字枚举状态为i,最后一个数为j,所能获得的最大分数。注意一些细节即可。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
typedef long long LL;
const int maxn=1<<17;
int cas;
int n;
LL f[maxn][16];
LL way[16],a[16];
int pp[16];
int p[16];
int main()
{
int T;
cin>>T;
while (T--)
{
printf("Case #%d:\n",++cas);
memset(way,-1,sizeof(way));
memset(pp,0,sizeof(pp));
cin>>n;
for (int i=0;i<n;i++)
{
cin>>a[i]>>p[i];
if (p[i]!=-1) pp[i]=1,way[p[i]]=i;
}
for (int i=1;i<(1<<n);i++)
for (int j=0;j<n;j++)
f[i][j]=-2e9;
if (way[0]!=-1)
{
f[1<<way[0]][way[0]]=0;
}
else
{
for (int i=0;i<n;i++)
if (!pp[i]) f[1<<i][i]=0;
}
for (int i=1;i<(1<<n);i++)
{
int l=0,x=i;
while (x) l+=x%2,x/=2;
l--;
if (way[l]!=-1)
{
for (int j=0;j<n;j++)
{
if (j==way[l]||!(i&(1<<j))||(way[l-1]!=-1&&way[l-1]!=j)) continue;
f[i][way[l]]=max(f[i][way[l]],f[i^(1<<way[l])][j]+a[j]*a[way[l]]);
}
continue;
}
for (int j=0;j<n;j++)
{
if (f[i][j]!=-2e9||!(i&(1<<j))||(way[l]!=-1&&way[l]!=j)) continue;
for (int k=0;k<n;k++)
{
if (j==k||!(i&(1<<k))||(way[l-1]!=-1&&way[l-1]!=k)) continue;
f[i][j]=max(f[i][j],f[i^(1<<j)][k]+a[k]*a[j]);
}
}
}
LL ans=-2e9;
for (int i=0;i<n;i++)
ans=max(ans,f[(1<<n)-1][i]);
cout<<ans<<endl;
}
return 0;
}
利用树的dfs序来维护每个节点到0的权值。每个子树都可以用dfs序中连续的一段表示。而此题,将一个零食机权值改变后,相当于将以这个点为根节点的子树所有权值减去/加上一个数。查询也是相当于查询以必经点为根节点的子树的权值的最大值。显然我们用一棵线段树维护即可。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
typedef __int64 LL;
struct data{
int l,r;
LL max,lazy;
}tr[4000001];
LL a[400050];
int pos;
int in[410000],out[410000];
int e[410000],pre[410000],last[410000];
LL val[410000];
int pp[410000];
int n,m;
int cas;
void build(int k,int s,int t)
{
tr[k].l=s;tr[k].r=t;
tr[k].lazy=0;
if(s==t)
{
tr[k].max=val[s];
return;
}
int mid=(s+t)>>1;
build(k<<1,s,mid);
build(k<<1|1,mid+1,t);
tr[k].max=max(tr[k<<1].max,tr[k<<1|1].max);
}
void pushdown(int k)
{
tr[k<<1].max+=tr[k].lazy;
tr[k<<1|1].max+=tr[k].lazy;
tr[k<<1].lazy+=tr[k].lazy;
tr[k<<1|1].lazy+=tr[k].lazy;
tr[k].lazy=0;
}
void change(int k,int a,int b,LL c)
{
int l=tr[k].l,r=tr[k].r;
if(a==l&&b==r)
{
tr[k].max+=(LL)c;
tr[k].lazy+=(LL)c;
return;
}
if(tr[k].lazy!=0) pushdown(k);
int mid=(l+r)>>1;
if(b<=mid) change(k<<1,a,b,c);
else if(a>mid) change(k<<1|1,a,b,c);
else change(k<<1,a,mid,c),change(k<<1|1,mid+1,b,c);
tr[k].max=max(tr[k<<1].max,tr[k<<1|1].max);
}
LL query(int k,int a,int b)
{
int l=tr[k].l,r=tr[k].r;
if (a==l&&b==r)
{
return tr[k].max;
}
if(tr[k].lazy!=0) pushdown(k);
int mid=(l+r)>>1;
LL res=-1e15;
if(b<=mid) res=max(res,query(k<<1,a,b));
else if(a>mid) res=query(k<<1|1,a,b);
else res=max(query(k<<1,a,mid),query(k<<1|1,mid+1,b));
tr[k].max=max(tr[k<<1].max,tr[k<<1|1].max);
return res;
}
void dfs(int x,LL now)
{
now+=a[x];
val[++pos]=now;
pp[x]=1;
in[x]=pos;
for (int i=last[x];i!=0;i=pre[i])
{
if (!pp[e[i]]) dfs(e[i],now);
}
out[x]=pos;
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
printf("Case #%d:\n",++cas);
pos=0;
int num=0;
memset(pp,0,sizeof(pp));
memset(last,0,sizeof(last));
scanf("%d %d",&n,&m);
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d %d",&x,&y);
x++,y++;
e[++num]=y;
pre[num]=last[x];
last[x]=num;
e[++num]=x;
pre[num]=last[y];
last[y]=num;
}
for (int i=1;i<=n;i++)
scanf("%I64d",&a[i]);
dfs(1,0);
build(1,1,n);
for (int i=1;i<=m;i++)
{
int op,x;
LL y;
scanf("%d",&op);
if (op==0)
{
scanf("%d %I64d",&x,&y);
x++;
change(1,in[x],out[x],y-a[x]);
a[x]=y;
}
else
{
scanf("%d",&x);
x++;
printf("%I64d\n",query(1,in[x],out[x]));
}
}
}
return 0;
}
动态规划。关键思路在于,我们只用考虑长度为2或者为3的等差数列。然后进行区间dp即可。f[i][j]表示i到j这段中最多删去多少个数字,那么首先继承f[i+1][j]和f[i][j-1]中较大的那个,然后考虑将[i,j]划分成两个区间[i,l],[l+1,j]。再考虑如果i,j两点构成等差,且区间[i+1,j-1]可以全部删去。再考虑i和一中间点l构成等差,l和j构成等差,i,l,j三点构成等差的情况即可。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
typedef long long LL;
map<int,int> S;
int g[400][400];
int a[400];
int f[400][400];
int n,m;
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
memset(g,0,sizeof(g));
memset(f,0,sizeof(f));
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
for (int i=1;i<=n;i++)
{
for (int j=i+1;j<=n;j++)
if (a[j]-a[i]==x) g[i][j]=1;
}
}
for (int k=2;k<=n;k++)
{
for (int i=1,j=k;j<=n;i++,j++)
{
for (int l=i;l<j;l++)
f[i][j]=max(f[i][j],f[i][l]+f[l+1][j]);
if (g[i][j] && f[i+1][j-1]==(j-1)-(i+1)+1)
f[i][j]=j-i+1;
for (int l=i+1;l<j;l++)
{
if (g[i][l] && f[i+1][l-1]==(l-1)-(i+1)+1) f[i][j]=max(f[i][j],2+f[i+1][l-1]+f[l+1][j]);
if (g[l][j] && f[l+1][j-1]==(j-1)-(l+1)+1) f[i][j]=max(f[i][j],2+f[l+1][j-1]+f[i][l-1]);
if (g[i][l] && g[l][j]&&a[j]-a[l]==a[l]-a[i]&&f[i+1][l-1]==(l-1)-(i+1)+1&&f[l+1][j-1]==(j-1)-(l+1)+1)
f[i][j]=j-i+1;
}
}
}
printf("%d\n",f[1][n]);
}
return 0;
}
递归处理即可。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
typedef long long LL;
int cas;
LL x,m,k,c;
int way[11000];
int pp[11000];
int tail,ini;
int main()
{
int T;
cin>>T;
while (T--)
{
cin>>x>>m>>k>>c;
printf("Case #%d:\n",++cas);
memset(pp,-1,sizeof(pp));
tail=0;
LL now=0;
for (int i=0;;i++)
{
now=now*10+x;
now%=k;
if (pp[now]==-1)
{
pp[now]=i;
way[tail++]=now;
}
else
{
ini=pp[now];
break;
}
}
int begin=ini;
m--;
if (m<=ini)
{
if (way[m]==c) printf("Yes\n");
else printf("No\n");
}
else
{
m-=ini;
m%=(tail-ini);
if (way[m+ini]==c) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
从小到大bfs,判断至少多少人在其后面。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
using namespace std;
typedef long long LL;
int pp[110000],e[110000],pre[110000],last[110000];
LL ans;
LL now;
int n,m;
void bfs(int x)
{
now++;
pp[x]=1;
for (int i=last[x];i!=0;i=pre[i])
{
if (!pp[e[i]]) bfs(e[i]);
}
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d %d",&n,&m);
memset(pp,0,sizeof(pp));
memset(last,0,sizeof(last));
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d %d",&x,&y);
e[i]=y;
pre[i]=last[x];
last[x]=i;
}
ans=0;
for (int i=1;i<=n;i++)
{
if (!pp[i])
{
now=0;
bfs(i);
ans+=now*i;
}
}
cout<<ans<<endl;
}
return 0;
}