6.2 模拟赛
我试试吧
A 多边形
题意:给定一个多边形,点有点权,边有加和乘两种,表示边的端点可以通过权值加或乘合并为一个节点,求断掉某一条边形成的链不断合并节点最后能合并出的最大权值
环形后效性处理+区间DP
有极多细节,考场上没发现只拿了40pts(咬牙切齿
考场上的代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=60;
inline int read(){
int x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int n,f[2*N][2*N],ans=0,val[2*N];
bool typ[2*N];
int main(){
n=read();
for(int i=1;i<=n;i++){
char k;
scanf("%c",&k);
if(k=='t') typ[i]=0;
else typ[i]=1;
val[i]=read();
}
for(int i=n+1;i<=2*n;i++) typ[i]=typ[i-n],val[i]=val[i-n];
for(int k=1;k<=n;k++){
memset(f,0,sizeof f);
for(int i=1;i<=2*n;i++) f[i][i]=val[i];
// cout<<k<<endl;
for(int len=2;len<=n;len++){
for(int i=k;i<=k+n-len;i++){
int j=i+len-1;
for(int op=i+1;op<=j;op++){
// cout<<f[i][j]<<" ";
if(typ[op]==0) f[i][j]=max(f[i][j],f[i][op-1]+f[op][j]);
else f[i][j]=max(f[i][j],f[i][op-1]*f[op][j]);
}
}
}
ans=max(ans,f[k][k+n-1]);
}
printf("%d
",ans);
return 0;
}
还是想的太少了
错误点:
- 数据中存在负数,负乘负得正,极小值有可能转移到极大值
- 没必要枚举删去的边,处理好答案之后可以直接查表
- 极小值的转移也有可能被极大值影响,要考虑到各种情况
改以后的:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=60;
inline int read(){
int x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
ll n,f[2*N][2*N],ans=0,val[2*N],f2[2*N][2*N];
bool typ[2*N];
int main(){
n=read();
for(int i=1;i<=n;i++){
char k;
scanf("%c",&k);
if(k=='t') typ[i]=0;
else typ[i]=1;
val[i]=read();
}
for(int i=n+1;i<=2*n;i++) typ[i]=typ[i-n],val[i]=val[i-n];
memset(f,-0x3f,sizeof f);
memset(f2,0x3f,sizeof f2);
for(int i=1;i<=2*n;i++) f[i][i]=val[i],f2[i][i]=val[i];
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=2*n;i++){
int j=i+len-1;
for(int op=i+1;op<=j;op++){
if(typ[op]==0){
f[i][j]=max(f[i][j],f[i][op-1]+f[op][j]);
f2[i][j]=min(f2[i][j],f2[i][op-1]+f2[op][j]);
}else{
f[i][j]=max(f[i][j],f[i][op-1]*f[op][j]);
f[i][j]=max(f[i][j],f2[i][op-1]*f2[op][j]);
f2[i][j]=min(f2[i][j],f[i][op-1]*f2[op][j]);
f2[i][j]=min(f2[i][j],f2[i][op-1]*f[op][j]);
f2[i][j]=min(f2[i][j],f2[i][op-1]*f2[op][j]);
}
}
}
}
for(int i=1;i<=n;i++) ans=max(ans,f[i][i+n-1]);
printf("%lld
",ans);
return 0;
}
B 龙妹妹买牛奶
题意:给定一棵树,选一些点,这些点之间的距离不能小于等于k,k取1或2
树形DP k=1的时候很简单 k=2的时候很简单但是哪个都没拿全分
考场上的码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=100010;
inline int read(){
int x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int k,n,e[N],ne[N],h[N],idx;
int f[N][2],dp[N][2][2],biao[N][2];
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int x,int fa){
f[x][0]=0;
f[x][1]=1;
// cout<<x<<" "<<fa<<endl;
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
if(j==fa) continue;
dfs1(j,x);
f[x][1]+=f[j][0];
f[x][0]+=max(f[j][1],f[j][0]);
}
return;
}
void dfs2(int x,int fa){
memset(biao,0,sizeof biao);
int sum=0;
dp[x][0][0]=0;
dp[x][0][1]=0;
dp[x][1][0]=1;
// cout<<x<<" "<<fa<<endl;
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
if(j==fa) continue;
dfs2(j,x);
biao[++sum][0]=dp[j][1][0];
biao[sum][1]=biao[sum-1][1]+max(dp[j][0][1],dp[j][0][0]);
dp[x][1][0]+=dp[j][0][0];
dp[x][0][0]+=max(dp[j][0][1],dp[j][0][0]);
}
for(int i=1;i<=sum;i++){
dp[x][0][1]=max(dp[x][0][1],biao[i][0]+biao[sum][1]-(biao[i][1]-biao[i-1][1]));
}
// cout<<endl<<x<<":"<<endl;
// cout<<"1 0: "<<dp[x][1][0]<<endl;
// cout<<"0 1: "<<dp[x][0][1]<<endl;
// cout<<"0 0: "<<dp[x][0][0]<<endl;
return;
}
void work1(){
dfs1(1,0);
printf("%d
",max(f[1][1],f[1][0]));
}
void work2(){
dfs2(1,0);
printf("%d
",max(dp[1][1][0],max(dp[1][0][1],dp[1][0][0])));
}
int main(){
memset(h,-1,sizeof h);
n=read();
k=read();
for(int i=1;i<n;i++){
int a,b;
a=read(),b=read();
add(a,b);add(b,a);
}
if(k==1){
work1();
}else{
work2();
}
return 0;
}
维生素B
-
我数组开小了
-
《k=2我A了一个点T了两个点WA了一个点但是我不知道我在推什么然后我看了看徐鰰的代码发现他的式子好像和我的一样》
-
我为啥要开三维数组
改过以后的:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=100010;
inline int read(){
int x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int k,n,e[2*N],ne[2*N],h[2*N],idx;
int f[2*N][2],biao[N];
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int x,int fa){
f[x][0]=0;
f[x][1]=1;
// cout<<x<<" "<<fa<<endl;
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
if(j==fa) continue;
dfs1(j,x);
f[x][1]+=f[j][0];
f[x][0]+=max(f[j][1],f[j][0]);
}
return;
}
void dfs2(int x,int fa){//多么简洁多么赏心悦目的代码来自Xiwon
f[x][0]=0;
f[x][1]=1;
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
if(j==fa) continue;
dfs2(j,x);
biao[x]+=f[j][0];
}
f[x][0]=biao[x];
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
if(j==fa) continue;
f[x][0]=max(f[x][0],f[j][1]+biao[x]-f[j][0]);
f[x][1]+=biao[j];
}
return;
}
void work1(){
dfs1(1,0);
printf("%d
",max(f[1][1],f[1][0]));
}
void work2(){
dfs2(1,0);
printf("%d
",max(f[1][0],f[1][1]));
}
int main(){
memset(h,-1,sizeof h);
n=read();
k=read();
for(int i=1;i<n;i++){
int a,b;
a=read(),b=read();
add(a,b);add(b,a);
}
if(k==1){
work1();
}else{
work2();
}
return 0;
}
C 不要62
题意:给你俩数,让你求俩数之间(包括俩数)数字中不含4和62的数的个数
数位DP
报零了/kk
我上升吧
考试的时候:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=15;
inline int read(){
int x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int l,r,f[N][N];
void init(){
memset(f,0,sizeof f);
f[0][0]=1;
for(int len=1;len<=7;len++)
for(int i=0;i<10;i++)
for(int j=0;j<10;j++)
if(i!=4&&(i!=6||j!=2)) f[len][i]+=f[len-1][j];
}
int cul(int x){
if(x==-1) return 0;
int op[N],len=0,res=0;
int n=x;
while(n){
op[++len]=n%10;
n/=10;
}
for(int i=len;i>0;i--){
for(int j=0;j<op[i];j++){
if(j!=4&&(j!=2||op[i+1]!=6)) res+=f[i][j];
}
if(op[i]==4||(op[i]==2&&op[i+1]==6)) break;
}
return res;
}
int main(){
init();
l=read(),r=read();
while(l!=0||r!=0){
//do something...
printf("%d
",cul(r)-cul(l-1));
l=read(),r=read();
}
return 0;
}
挺忙的
- cul()函数是求[0,x)的数,不是[0,x]
- cul()里面len+1的地方没定义,用到了会随机赋值,啥也不是
改以后:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=15;
inline int read(){
int x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int l,r,f[N][N];
void init(){
memset(f,0,sizeof f);
f[0][0]=1;
for(int len=1;len<=7;len++)
for(int i=0;i<10;i++)
for(int j=0;j<10;j++)
if(i!=4&&!(i==6&&j==2)) f[len][i]+=f[len-1][j];
}
int cul(int x){
int op[N],len=0,res=0;
int n=x;
while(n){
op[++len]=n%10;
n/=10;
}
op[len+1]=0;
for(int i=len;i>0;i--){
for(int j=0;j<op[i];j++){
if(j!=4&&!(j==2&&op[i+1]==6)) res+=f[i][j];
}
if(op[i]==4||(op[i]==2&&op[i+1]==6)) break;
}
return res;
}
int main(){
init();
l=read(),r=read();
while(l!=0||r!=0){
//do something...
printf("%d
",cul(r+1)-cul(l));
l=read(),r=read();
}
return 0;
}