2287: 【POJ Challenge】消失之物
首先我們有f[]表示所有物品都考慮時的方案數或者最大價值。
使用g[j]表示不選x物品時總重量爲j的方案數或者價值最大值,就可以想出如何計算出不選x物品時的方案數或者最大價值了。
g[j]=f[j]-g[j-v]
(因爲g[j-v]可以表示爲剛好選了x的方案數)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=2000+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int n,m;
int f[maxn],g[maxn];
int w[maxn];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&w[i]);
f[0]=1;
for(int i=1;i<=n;i++){
for(int j=m;j>=w[i];j--){
f[j]=(f[j]+f[j-w[i]])%10;
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
if(j<w[i])g[j]=f[j];
else{
g[j]=(f[j]-g[j-w[i]]+10)%10;
}
}
for(int j=1;j<=m;j++){
printf("%d",g[j]);
}
printf("\n");
}
return 0;
}
Tree
https://ac.nowcoder.com/acm/contest/140/E
也是用可撤銷的套路,不過是對一棵子樹撤銷,還是有點厲害的
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=1e5+15;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
ll pow_mod(ll a,ll b){
ll ret=1;
while(b){
if(b&1)ret=ret*a%mod;
a=a*a%mod;
b>>=1;
}
return ret;
}
int n,m;
struct edge{
int to,nxt;
}e[maxn];
int head[maxn];
int tot;
void adde(int u,int v){
e[tot].to=v;
e[tot].nxt=head[u];
head[u]=tot++;
}
struct node{
ll d[11];
}dp[maxn];
node uni(node a,node b){
node ret=a;
for(int i=10;i>=2;i--){
for(int j=1;j<i;j++){
ret.d[i]=(ret.d[i]+ret.d[i-j]*b.d[j]%mod)%mod;
}
}
return ret;
}
node disuni(node a,node b){
node ret=a;
for(int i=2;i<=10;i++){
for(int j=1;j<i;j++){
ret.d[i]=(ret.d[i]-ret.d[i-j]*b.d[j]%mod+mod)%mod;
}
}
return ret;
}
ll val[maxn];
int fa[maxn];
int line[11];
int cc;
void dfs(int u){
for(int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
dfs(v);
dp[u]=uni(dp[u],dp[v]);
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&val[i]);
dp[i].d[1]=val[i];
}
for(int i=2;i<=n;i++){
scanf("%d",&fa[i]);
adde(fa[i],i);
}
dfs(1);
int op,a,b;
while(m--){
scanf("%d%d%d",&op,&a,&b);
cc=0;
int ba=a;
while(ba&&cc<10){
line[cc++]=ba;
ba=fa[ba];
}
if(op==0){
for(int i=cc-1;i>=1;i--){
dp[line[i]]=disuni(dp[line[i]],dp[line[i-1]]);
}
ll t=b*pow_mod(val[a],mod-2)%mod;
for(int i=1;i<=10;i++)dp[a].d[i]=(dp[a].d[i]*t)%mod;
for(int i=1;i<cc;i++){
dp[line[i]]=uni(dp[line[i]],dp[line[i-1]]);
}
val[a]=b;
}
else if(op==1){
for(int i=cc-1;i>=1;i--){
dp[line[i]]=disuni(dp[line[i]],dp[line[i-1]]);
}
for(int i=2;i<cc;i++){
dp[line[i]]=uni(dp[line[i]],dp[line[i-1]]);
}
cc=0;
fa[a]=b;
int ba=a;
while(ba&&cc<10){
line[cc++]=ba;
ba=fa[ba];
}
for(int i=cc-1;i>=2;i--){
dp[line[i]]=disuni(dp[line[i]],dp[line[i-1]]);
}
for(int i=1;i<cc;i++){
dp[line[i]]=uni(dp[line[i]],dp[line[i-1]]);
}
}
else if(op==2){
if(cc==1){printf("%lld\n",dp[a].d[b]);continue;}
node ans=disuni(dp[line[cc-1]],dp[line[cc-2]]);
for(int i=cc-2;i>=1;i--){
ans=uni(disuni(dp[line[i]],dp[line[i-1]]),ans);
}
ans=uni(dp[a],ans);
printf("%lld\n",ans.d[b]);
}
}
return 0;
}
5429 多重揹包
http://codevs.cn/problem/5429/
用單調隊列優化揹包,就是對每個餘數分開做,然後維護單調遞減的隊列即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=7000+15;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int n,m;
int v[maxn],w[maxn],c[maxn];
int dp[2][maxn];
pii que[maxn];
void work(int *f1,int *f2,int vv,int ww,int cc){
for(int b=0;b<vv;b++){
int head=0,tail=0;
for(int k=0;k*vv+b<=m;k++){
int j=b+k*vv;
pii cnt=mp(k,f2[j]-k*ww);
while(tail>head&&cnt.se>=que[tail-1].se)tail--;
que[tail++]=cnt;
while(k-que[head].fi>cc)head++;
f1[j]=que[head].se+k*ww;
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&v[i],&w[i],&c[i]);
work(dp[i%2],dp[(i+1)%2],v[i],w[i],c[i]);
}
printf("%d\n",dp[n%2][m]);
return 0;
}