模拟题,直接每次模拟删除和加入就好。
注意两个点:
1.答案开 l o n g l o n g long\;long longlong
2. v i s vis vis数组要 5 e 7 5e7 5e7
#include
#define ll long long
#define mod 1000000007
#define rep(i,a,b) for(ll (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int maxn=3e6+10;
const int maxm=5e7+10;
ll x[maxn],ans[maxn],sum[maxn],q[maxn];
bool vis[maxm];
ll m,n,a,b,c;
template <class t> inline void read(t &x) {
x=0;int f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
x*=f;
}
void readdata() {
read(n),read(m),read(a),read(b),read(c);
x[0]=0;
rep(i,1,m) {
x[i]=(a*x[i-1]+b)%(2*n*c);
}
}
void work() {
rep(i,1,m) {
if(x[i]<(n*c)) {
ll pos=floor(x[i]/c)+1;
if(vis[pos]==0) {
vis[pos]=1;
q[i]=(q[i-1]+1)%mod;
ans[i]=(ans[i-1]+pos)%mod;
}
else {
q[i]=(q[i-1])%mod;
ans[i]=(ans[i-1])%mod;
}
}
if(x[i]>=(n*c)) {
ll pos=floor(x[i]/c)-n+1;
if(vis[pos]==1) {
vis[pos]=0;
q[i]=(q[i-1]-1)%mod;
ans[i]=(ans[i-1]-pos)%mod;
}
else {
q[i]=(q[i-1])%mod;
ans[i]=(ans[i-1])%mod;
}
}
}
ll ans1=0,ans2=0;
rep(i,1,m) ans1=(ans1+q[i])%mod;
rep(i,1,m) ans2=(ans2+ans[i])%mod;
printf("%lld %lld",ans1,ans2);
}
int main() {
//freopen("schedule.in","r",stdin);
// freopen("schedule.out","w",stdout);
readdata();
work();
return 0;
}
倍增优化数的遍历
对于每一个节点,做出的贡献都是唯一的,则通过倍增的方式找到它做出贡献的那个点,在判断是左儿子还是右儿子就可以了
有个小优化
现将 v [ i ] v[i] v[i]减一,跳到做贡献的那个点的下方,方便判断是左儿子还是右儿子。当距离为 v [ i ] v[i] v[i]时,我们将 v [ i ] v[i] v[i]拆成二进制数,应为是要将这个点向上走 v [ i ] v[i] v[i]这么多步,则对于这个二进制数,哪一位是 1 1 1,我们就可以向上跳 2 2 2的这么多位的次方
比如7,我们就可以先跳 2 0 2^0 20,再跳 2 1 2^1 21,再跳 2 2 2^2 22
#include
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int maxm=1e3+10;
const int maxn=2e5+10;
int n,cnt;
int a[maxn],head[maxn],l[maxn],r[maxn],dep[maxn],f[maxn][21],son[maxn];
template <class t> inline void read(t &x) {
x=0;int f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
x*=f;
}
struct node{
int v,nex;
}e[maxn];
void add(int u,int v) {
e[++cnt].v=v;
e[cnt].nex=head[u];
head[u]=cnt;
}
void readdata() {
read(n);
rep(i,1,n) read(a[i]);
rep(i,1,n) {
int x,y;
read(x),read(y);
if(x!=0) {add(i,x);son[x]=1;}
if(y!=0) {add(i,y);son[y]=0;}
}
}
void dfs_first(int u,int fa,int deep) {
dep[u]=deep;
f[u][0]=fa;
rep(i,0,19) f[u][i+1]=f[f[u][i]][i];
for(int i=head[u];i;i=e[i].nex) {
int v=e[i].v;
if(v==fa) continue;
dfs_first(v,u,deep+1);
}
}
void work() {
memset(l,false,sizeof(l));
memset(r,false,sizeof(r));
dfs_first(1,0,1);
rep(u,1,n) {
int x=u;a[x]--;
rep(i,0,19) {
if((1<<i)&a[u]) x=f[x][i];
}
if(son[x]) l[f[x][0]]++;
else r[f[x][0]]++;
}
rep(i,1,n) {
printf("%d %d\n",l[i],r[i]);
}
}
int main() {
// freopen("node.in","r",stdin);
// freopen("node.out","w",stdout);
readdata();
work();
return 0;
}
转移方程
f [ u ] [ o ] = m a x ( f [ u ] [ o ] g [ i ] + f [ v ] [ j ] ) f[u][o] =max(f[u][o]g[i] +f[v][j]) f[u][o]=max(f[u][o]g[i]+f[v][j])
f [ i ] [ k ] f[i][k] f[i][k]表示以 i i i为根,选择的点距离它的距离至少为 k k k的最优解
#include
#define inf 100000000
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int maxn=1e5+10;
const int maxm=1e3+10;
int n,K,cnt;
int a[maxn],head[maxn];
int f[maxn][110],g[maxn];
template <class t> inline void read(t &x) {
x=0;int f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
x*=f;
}
struct node{
int v,nex;
}e[maxn<<1];
void add(int u,int v) {
e[++cnt].v=v;
e[cnt].nex=head[u];
head[u]=cnt;
}
void readdata() {
read(n);read(K);
rep(i,1,n) read(a[i]);
rep(i,1,n-1) {
int x,y;
read(x),read(y);
add(x,y);add(y,x);
}
}
void dfs(int u,int fa) {
f[u][0]=a[u];
for(int i=head[u];i;i=e[i].nex) {
int v=e[i].v;
if(v==fa) continue;
dfs(v,u);
memcpy(g,f[u],sizeof(f[u]));
for (int a = 0;a <=K;++a) {
for (int b = K - a;b <= K;++b) {
f[u][min(a,b+1)] = max(f[u][min(a,b+1)],g[a]+f[v][b]);
}
}
}
}
void work() {
int ans=-inf;
dfs(1,0);
rep(i,1,K) ans=max(ans,f[1][i]);
printf("%d\n",ans);
}
int main() {
freopen("score.in","r",stdin);
//freopen("score.out","w",stdout);
readdata();
work();
return 0;
}