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 ",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 ",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(" "); } 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 ",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都没开。。。