广二集训 day4
T1 DP
考虑实际上合并颜色的过程就相当于一棵树的节点合并,正着处理不太方便,因为我们总不能很方便地记录状态,考虑倒过来思考,最后的
炮弹颜色是什么,又是怎样合成的?
这样,我们能找到一个几乎一样的子问题:用来合成最后一个炮弹的每个炮弹,颜色是什么,每个炮弹又是如何生成的。
不妨考虑来设计这个状态:
-
f[i,j] 表示使用i个球合成一个颜色j的方案数,不难发现转移复杂度爆了
-
优化为 f[i,j,k] 表示使用i个球合成k个颜色j的方案数 , 这样来说时间复杂度就可以了
等等,这个状态好像有点问题,似乎出现了一种反规则的事件,这样做貌似会使我们的转化不合法:
1 1 1 4
1 1 1 2 2|||2
1 1 1 2 2|||3 3 3
1 1 1 2 2|||2 2 3 3
这样不就提前转化了吗
我们更改DP状态为 f[i,j,k,z] 表示本过程头部合成过程中不能出现z颜色,注意是一直不能出现,而不是最后一次合并,因为一旦在头部出现就会发生“提前转化”
- \(f[i,j,k,z]=\sum_{s1} f[s1,j,1,z]*f[i-s1,j,k-1,j]\) (为什么会面要限制头部不能出现 \(j\) ,因为我们DP要严格遵循式子的意义,这样才能不重不漏)
- \(f[i,j,1,z]=\sum_{y \neq z} f[i,y,b[y],z]\)
int f[505][12][12][12];
signed main() {
cin>>n>>m;
for(int i=1;i<=m;i++) {
a[i]=read(),b[i]=read();
c[b[i]].push_back(i);
}
for(int i=1;i<=m;i++)
for(int j=0;j<=m;j++) f[1][i][1][j]=1;
for(int i=2;i<=n;i++)
for(int nw=1;nw<=m;nw++) {
for(int cnt=2;cnt<=a[nw];cnt++) {
for(int no=0;no<=m;no++) {
for(int s1=1;s1<i;s1++)
f[i][nw][cnt][no]+=f[s1][nw][1][no]*f[i-s1][nw][cnt-1][nw]%P,
f[i][nw][cnt][no]%=P;
}
}
for(int no=0;no<=m;no++)
if(nw!=no) f[i][b[nw]][1][no]+=f[i][nw][a[nw]][no],
f[i][b[nw]][1][no]%=P;
}
int ans=0;
for(int i=1;i<=m;i++)
ans+=f[n][i][1][0],ans%=P;
cout<<ans;
return 0;
}
T2 随机化乱搞
【题目背景】
《For The King》是一款结合桌游和 roguelike 类型元素的跨界策略 RPG
游戏。这段惊心动魄的冒险,还要从法汝大陆开始,国王突遭不测,女王紧急召唤勇士们踏上命运之路,破解谜团阻止厄运,一路升级寻找真相。
小 T,小 B 和小 Z 入坑了《4 the king》。游玩的时候他们选择了一个"以
99%的概率成功,1%的概率死亡"的选项,然后似了。
小 T 重开了个单人档。
【题目描述】
小 T 创建存档时,得知了这个存档的地图:地图上有 \(n\) 个格子,被 \(n-1\)
条边连通,构成一棵树。地图上共有 \(n\) 只怪物,第 \(i\) 只怪物在编号为 \(i\)
的格子上。在开始游戏前,小 T
可以选中一个连通块,然后清除这个连通块上的怪物,并获得相应的增益。
具体地,小 T 有两种属性,攻击力与怒气值,初始均为 \(0\)。第 \(i\)
个怪如果在连通块内,就会给小 T 增加 \(a_i\) 点攻击力以及 \(b_i\)
点怒气值。此外,第 \(i\) 只怪物有 \(c_i\) 点血量。小 T
在清除怪物后,还会获得一定量的金币。设 \(A\) 为小 T 最终的攻击力,\(B\) 为小
T 最终的怒气值,\(C\) 为清除的怪物血量之和,那么小 T 会获得 \(AB-C\)
个金币。由于金币在这个游戏中很重要,所以小 T
想知道如何能获得最多的金币。小 T
也可以选择直接跳过这个游戏前的阶段,那么他会获得 \(0\) 个金币。
(注:最终的攻击力 \(A\) 即为所有选中怪物的 \(a_i\) 之和,\(B,C\) 同理)
小 T 会重开很多个档,所以本题有多组询问。
【输入格式】
第一行为数据组数 \(T\),接下来依次输入每组数据。对于每组数据:
第一行一个整数 \(n\),表示地图上的格子数。
接下来 \(n\) 行,每行三个整数 \(a_i,b_i,c_i\),代表第 \(i\) 个怪的属性。
再接下来 \(n-1\) 行每行两个整数,表示地图上的一条边。
【输出格式】
对于每组数据,输出两行。
第一行一个整数 \(ans\),表示获取的最大金币数。
第二行一个长度为 \(n\) 的 01 字符串表示方案。第 \(i\) 个字符为 1
表示选中了第 \(i\)
个格子,否则没有选中。(如果选择跳过这个阶段,则需要输出 \(n\) 个 0)
————————————
首先这个题看着就很能乱搞
考虑说如果确定结束时A与B的值,那么对于一个点来说,他加不加入我们是可以贪心的
if((ra-A[i])*(rb-B[i])+C[i]<=ra*rb) {
A[p]+=A[i],B[p]+=B[i],C[p]+=C[i];
}
所以我们随机一个A,B跑上述贪心,然后得到一个近似解,在近似解周围再跑贪心,那么就可以通过水数据
int T,n,a[N],b[N],c[N],A[N],B[N],C[N],D;
int sa,sb,ra,rb,wa,wb,tmp;
vector<int > v[N];
bitset<N > ans[N],vis;
void dfs(int p,int f) {
A[p]=a[p],B[p]=b[p],C[p]=c[p];
for(int i:v[p]) {
if(i==f) continue;
dfs(i,p);
if((ra-A[i])*(rb-B[i])+C[i]<=ra*rb) {
A[p]+=A[i],B[p]+=B[i],C[p]+=C[i];
}
}
if(A[p]*B[p]-C[p]>tmp) {
tmp=A[p]*B[p]-C[p];wa=ra,wb=rb;
}
}
void answer(int p,int f) {
A[p]=a[p],B[p]=b[p],C[p]=c[p];
ans[p][p]=1;
// cout<<p<<" "<<ans[p][p]<<endl;
for(int i:v[p]) {
if(i==f) continue;
answer(i,p);
if((wa-A[i])*(wb-B[i])+C[i]<wa*wb) {
A[p]+=A[i],B[p]+=B[i],C[p]+=C[i];
ans[p]|=ans[i];
// cout<<i<<" "<<p<<" "<<ans[i][i]<<endl;
// for(int j=1;j<=n;j++) printf("%lld",(int)ans[p][j]);cout<<endl;
}
}
if(A[p]*B[p]-C[p]==tmp) {
tmp=A[p]*B[p]-C[p];wa=ra,wb=rb;
vis=ans[p];
// cout<<p<<" ";
}
}
void tidy() { for(int i=1;i<=n;i++) A[i]=B[i]=C[i]=0; }
void Solve() {
mt19937 t1(time(0));
mt19937 t2(t1());mt19937 t3(t2());mt19937 t4(t3());mt19937 t5(t4());mt19937 t6(t5());
mt19937 rd(t5());
int number=0;
while(number<=up/n) {
ra=(rd()%sa+1),rb=(rd()%sb+1);
ra>>=(rd()%8),rb>>=(rd()%8);
dfs(1,0);tidy();
number++;
}
number=0;
sa=wa,sb=wb;
while(number<=up/n) {
ra=(int)(sa+rd()%(sa/2+1)-sa/4+1);
rb=(int)(sb+rd()%(sb/2+1)-sb/4+1);
dfs(1,0);tidy();
number++;
}
answer(1,0);
cout<<tmp<<endl;
for(int i=1;i<=n;i++) printf("%lld",(int)vis[i]);cout<<endl;
}
void Clear(){
sa=sb=0;wa=wb=0,tmp=0;vis.reset();
for(int i=1;i<=n;i++) v[i].clear(),a[i]=b[i]=c[i]=0,ans[i].reset();
}
signed main() {
cin>>T;
while(T--) {
cin>>n;
for(int i=1;i<=n;i++) {
a[i]=read(),b[i]=read(),c[i]=read();
sa+=a[i],sb+=b[i];
}
for(int i=1;i<n;i++) {
int x=read(),y=read();
v[x].push_back(y),v[y].push_back(x);
}
Solve();Clear();
}
return 0;
}

T1:超级好的DP
T2:随机化唐题罢了
浙公网安备 33010602011771号