9.16:
A: 将其变为一个序列,然后对于A[i]-=i,然后求最长不下降子序列即可
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cctype>
using namespace std;
int read()
{
int f=1,x=0;
char ch=' ';
for(;!isdigit(ch);ch=getchar())if(ch=='-')f*=-1;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return f*x;
}
int n,son[100010][2],r[100010],a[100010],fid[100010],cnt;
void dfs(int x)
{
if(son[x][0])
dfs(son[x][0]);
fid[++cnt]=x;
if(son[x][1])
dfs(son[x][1]);
}
int f[100010],g[100010];
int work()
{
int ans=0;
memset(g,127,sizeof(g));
g[0]=-g[0];
for(int i=1;i<=n;i++)
{
int x=upper_bound(g,g+n+1,a[i])-g;
ans=max(ans,x);
g[x]=a[i];
}
return ans;
}
int main()
{
n=read();
for(int i=2;i<=n;i++)
{
int f=read();
int s=read();
s--;
son[f][s]=i;
}
for(int i=1;i<=n;i++)
r[i]=read();
dfs(1);
for(int i=1;i<=n;i++)
a[i]=r[fid[i]];
for(int i=1;i<=n;i++)
a[i]-=i;
int ans=n-work();
printf("%d\n",ans);
return 0;
}
B:dp[i][j]表示选了i个数,有j个5,最多2的个数,转移到底就好了
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
int f[5][510][6010],five[510],two[510];
long long a[510];
long long read()
{
long long f=1,x=0;
char ch=' ';
for(;!isdigit(ch);ch=getchar())if(ch=='-')f*=-1;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return f*x;
}
int main()
{
int n,ans=0,res=0,k,cnt=0;
n=read();
k=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
while(a[i]%5==0)
{
five[i]++;cnt++;
a[i]/=5;
}
while(a[i]%2==0)
{
two[i]++;
a[i]/=2;
}
}
memset(f,-1,sizeof(f));
f[0][0][0]=0;
f[1][0][0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
for(int u=0;u<=cnt;u++)
{
if(u>=five[i]&&f[(i-1)&1][j-1][u-five[i]]!=-1)
f[i&1][j][u]=max(f[(i-1)&1][j][u],f[(i-1)&1][j-1][u-five[i]]+two[i]);
else f[i&1][j][u]=f[(i-1)&1][j][u];
}
for(int u=1;u<=cnt;u++)
{
if(u>f[n&1][k][u])
ans=f[n&1][k][u];
else ans=u;
res=max(ans,res);
}
printf("%d",res);
return 0;
}
C:二分以后是求最大团,(然后我就闲的没事退火退了4页才过。。。)
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
const int INF=1e9;
int a[101][101];
int b[5000010];
int vis[5000010];
int ans;
int read()
{
int f=1,x=0;
char ch=' ';
for(;!isdigit(ch);ch=getchar())if(ch=='-')f*=-1;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return f*x;
}
int n,k;
int fi(int x)
{
for(int i=1;i<=n;i++) vis[i]=0;
int now=0;
for(int i=1;i<=n;i++)
{
int f=1;
for(int j=1;j<i;j++)
{
if(vis[b[j]]&&a[b[i]][b[j]]>x)
{
f=0;
break;
}
}
if(f) vis[b[i]]=1;
}
for(int i=1;i<=n;i++) now+=vis[i];
return now;
}
void ra(int row)
{
double t=100.0;
while(t>1e-8)
{
int x=rand()%n+1;
int y=rand()%n+1;
if(x==y) continue;
swap(b[x],b[y]);
int now=fi(row);
int fin=ans-now;
if(ans<now) ans=now;
else if(exp((double)((double)fin/t))*RAND_MAX<=rand())
swap(b[x],b[y]);
t*=0.9812;
}
}
bool check(int x)
{
ans=0;
for(int i=1;i<=100;i++)
{
random_shuffle(b+1,b+1+n);
ra(x);
if(ans>=k) return 1;
}
return 0;
}
int main()
{
srand((unsigned)time(NULL));
n=read(); k=read();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a[i][j]=read();
}
}
for(int i=1;i<=n;i++) b[i]=i;
int l=1,r=INF;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%d\n",ans);
return 0;
}
总结:T1被吓到然后就没写,考完后发现60-70是很好拿的
T2用贪心乱搞竟然过了85
T3当时时间只够写个20 分了,考完发现其实进一步优化能拿到更多的分数
9.19
A:输出n遍n(然后考场上zkt说我对了但我这个如果因为自己的问题出了锅就不怪他了)然后我就完美的写错了文件名
#include<cstdio>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
int nn=n;
while(nn--)
printf("%d",n);
printf("\n");
}
return 0;
}
B:求出最长链的中心,把它作为根,然后以子树中最长链的长度为权值取点或删点即可
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
using namespace std;
int read()
{
int f=1,x=0;
char ch=' ';
for(;!isdigit(ch);ch=getchar())if(ch=='-')f*=-1;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return f*x;
}
int maxm(int x,int y)
{
if(x>y) return x;
else return y;
}
struct node
{
int v,last;
bool flag;
}e[5000010];
int in[5000010],cnt=0;
int dep[5000010],size[5000010],len[5000010];
int f[5000010];
int check2[5000010];
int anss;
struct Node
{
int x,y;
}fin[5000010];
bool leaf[5000010];
int check[5000010];
void add(int x,int y)
{
e[++cnt].v=y;
e[cnt].flag=1;
e[cnt].last=in[x];
in[x]=cnt;
}
bool cmp(Node a,Node b)
{
return a.x>b.x;
}
void dfs(int cur,int fa)
{
dep[cur]=dep[fa]+1;
int i,t,tmp=0;
size[cur]=1;
for(i=in[cur];i;i=e[i].last)
{
t=e[i].v;
if(t!=fa)
{
f[t]=cur;
dfs(t,cur);
tmp=max(tmp,len[t]);
size[cur]+=size[t];
}
}
if(size[cur]==1)len[cur]=0;
else len[cur]=tmp+1;
return;
}
void findfs(int cur,int fa)
{
int i,t,flag=1;
for(i=in[cur];i;i=e[i].last)
{
t=e[i].v;
if(t==fa) continue;
if(!check2[t]) continue;
flag=0;
findfs(t,cur);
}
if(flag) leaf[cur]=1;
return;
}
int cou=0;
int find(int x)
{
if(x!=f[x])
{
cou++;
x=find(f[x]);
}
return x;
}
int ans=-1;
int find2(int x)
{
if(x!=f[x])
{
cou++;
if(cou==(ans-1)/2+1)
return f[x];
else
x=find2(f[x]);
}
return 1;
}
int main()
{
//freopen("ex.in","r",stdin);
int n,k;
n=read();
k=read();
for(int i=1;i<=n-1;i++)
{
int x,y;
x=read();
y=read();
add(x,y);
add(y,x);
check[x]++;
check[y]++;
}
int cnt=0;
int flag=0;
for(int i=1;i<=n;i++)
{
if(check[i]==1)
{
cnt++;
}
else
{
if(check[i]!=2)
{
flag=1;
break;
}
}
}
if(!flag&&cnt==2)
{
if((n-k)%2)
printf("%d",(n-k)/2+1);
else
printf("%d",(n-k)/2);
return 0;
}
dfs(1,0);
f[1]=1;
for(int i=1;i<=n;i++)
{
if(leaf[i])
{
find(i);
//printf("%lld\n",cou);
if(cou>ans)
{
ans=cou;
anss=i;
}
cou=0;
}
}
cou=0;
anss=find2(anss);
dfs(anss,0);
for(int i=1;i<=n;i++)
fin[i].x=len[i],fin[i].y=i;
sort(fin+1,fin+1+n,cmp);
for(int i=1;i<=k;i++)
check2[fin[i].y]=1;
findfs(anss,0);
int ffans=-1;
for(int i=1;i<=k;i++)
{
if(leaf[fin[i].y])
ffans=maxm(ffans,fin[i].x);
}
printf("%d",ffans);
return 0;
}
C:手写bitset
以实现查找第k
小。其实std::bitset上2分也好不过zkt说std::bitset多一个log
这个因为需要一些毒瘤的ckw的读入优化,就不放代码了
总结:T1:在题目中已经说过了。。。
T2:当时不知道为什么,就把两个并查集写串了,然后对着大样例调了2h.....
T3:考场上就只在调T2了,T3都没开。。。