10.10 上午 考试
T1
40:
深搜
60:
m<=$10^5$时,可以dp,f[i]表示前i个星球最多的矿
f[i]=max(f[i-4],f[i-7])+val[i]
100:
打表发现只有 1 2 3 5 6 9 10 13 17 不能由4、7组合出来
所以只要把>18的距离离散成18,还像60那样dp就行了
$O(18n)$
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
inline int read()
{
char q=getchar();int ans=0;
while(q<'0'||q>'9')q=getchar();
while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
return ans;
}
const int N=100006;
struct JI
{
int pos,val;
bool friend operator < (JI a,JI b)
{
return a.pos<b.pos;
}
}ji[N];
int n,m;
int f[N*20],hh[N*20];
int ans;
int len;
void chu()
{
sort(ji+1,ji+1+n);
int las=0,temp;
for(int i=1;i<=n;++i)
{
if(ji[i].pos-ji[i-1].pos>17)
temp=18;
else
temp=ji[i].pos-ji[i-1].pos;
hh[las+temp]+=ji[i].val;
las+=temp;
}
len=las;
}
void work()
{
int temp;
mem(f,-60);
f[0]=0;
for(int i=0;i<=len;++i)
{
if(f[i]<-1000)
continue;
if(f[i+4]<f[i]+hh[i+4])
f[i+4]=f[i]+hh[i+4];
if(f[i+7]<f[i]+hh[i+7])
f[i+7]=f[i]+hh[i+7];
}
for(int i=0;i<=len;++i)
if(ans<f[i])
ans=f[i];
}
int main(){
n=read();m=read();
for(int i=1;i<=n;++i)
ji[i].val=read(),ji[i].pos=read();
chu();
work();
cout<<ans;
}
T2
Aavg 平均数
原式可以化简:
$$ (n+m-1)\sum_{i=1}^{n+m-1}(A_i-Aavg)^2$$
$$ ((n+m-1)\sum_{i=1}^{n+m-1}A_{i}^{2})-sum^2$$
定义f[i][j][k] 为i行j列当前sum=k时$A_{i}^2$的最小值
然后从f[i-1][j][k]和f[i][j-1][k]转移就行了
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define dd double
using namespace std;
const int N=36;
int T;
int n,m,sum;
int a[N][N];
int f[33][33][27066];
int work()
{
mem(f,60);
int qqq=f[0][0][0];
int hhh=n+m-1,temp;
f[1][0][0]=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
for(int k=a[i][j];k<=sum;++k)
{
if(f[i-1][j][k-a[i][j]]!=qqq)
{
temp=f[i-1][j][k-a[i][j]]+hhh*a[i][j]*a[i][j];
if(f[i][j][k]>temp)
f[i][j][k]=temp;
}
if(f[i][j-1][k-a[i][j]]!=qqq)
{
temp=f[i][j-1][k-a[i][j]]+hhh*a[i][j]*a[i][j];
if(f[i][j][k]>temp)
f[i][j][k]=temp;
}
}
int ans=0x7fffffff;
for(int i=a[n][m];i<=sum;++i)
if(f[n][m][i]!=qqq)
{
temp=f[n][m][i]-i*i;
if(ans>temp)
ans=temp;
}
return ans;
}
int main(){
//freopen("T2.in","r",stdin);
//freopen("T2.out","w",stdout);
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
sum=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
scanf("%d",&a[i][j]);
sum+=a[i][j];
}
printf("%d\n",work());
}
}
T3
M是非常小的,所以异或之后受影响的只是低位,再dfs的时候记录下来低位是那个的个数即可
(我还在想异或会不会有什么结合律之类的...)
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
inline int read()
{
char q=getchar();int ans=0;
while(q<'0'||q>'9')q=getchar();
while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
return ans;
}
const int N=100006;
struct son
{
int v,next,w;
}a1[N*2];
int first[N*2],e;
void addbian(int u,int v,int w)
{
a1[e].v=v;
a1[e].w=w;
a1[e].next=first[u];
first[u]=e++;
}
int n,M,mod;
int gget()
{
int tt=M;
while(tt!=(tt&(-tt)))
tt-=(tt&(-tt));
return tt<<1;
}
int fa[N],sh[N][21],xi[N][21];
int xihe[N],shhe[N],size[N];
int t[21];
void dfs1(int x)
{
int temp;
size[x]=1;
for(int i=first[x];i!=-1;i=a1[i].next)
{
temp=a1[i].v;
if(temp==fa[x])
continue;
fa[temp]=x;
dfs1(temp);
size[x]+=size[temp];
xihe[x]+=(xihe[temp]+a1[i].w*size[temp]);
mem(t,0);
++t[a1[i].w%mod];
for(int j=0;j<mod;++j)
t[(j+a1[i].w)%mod]+=xi[temp][j];
for(int j=0;j<mod;++j)
xi[x][j]+=t[j];
}
}
int bb[21];
void dfs2(int x)
{
int temp;
for(int i=first[x];i!=-1;i=a1[i].next)
{
temp=a1[i].v;
if(temp==fa[x])
continue;
shhe[temp]+=(shhe[x]+xihe[x]-(xihe[temp]+a1[i].w*size[temp])+(size[1]-size[temp])*a1[i].w);
mem(t,0);mem(bb,0);
++t[a1[i].w%mod];
for(int j=0;j<mod;++j)
t[(j+a1[i].w)%mod]+=xi[temp][j];
for(int j=0;j<mod;++j)
t[j]=(xi[x][j]-t[j]+sh[x][j]);
++bb[a1[i].w%mod];
for(int j=0;j<mod;++j)
bb[(a1[i].w+j)%mod]+=t[j];
for(int j=0;j<mod;++j)
sh[temp][j]=bb[j];
dfs2(temp);
}
}
int main(){
//freopen("T3.in","r",stdin);
mem(first,-1);
n=read();M=read();
mod=gget();
if(mod==0)mod=1;
int tin1,tin2,tin3;
for(int i=1;i<n;++i)
{
tin1=read();tin2=read();tin3=read();
addbian(tin1,tin2,tin3);
addbian(tin2,tin1,tin3);
}
dfs1(1);
dfs2(1);
int temp;
for(int i=1;i<=n;++i)
{
temp=shhe[i]+xihe[i];
for(int j=0;j<mod;++j)
temp+=(sh[i][j]+xi[i][j])*((j^M)-j);
printf("%d\n",temp);
}
}
总结:
考试的时候,一定要努力想,不要脑子抽风...