2018ICPC青岛现场赛 重现训练
先贴代码,以及简要题解。
和一个队友下午双排打了一下,队友光速签到,我签的J被嫌弃写得慢以及演员。。。然后我秒出了E了思路然而难以置信这么简单的思路当时才过了十几个,于是发现D、F不是太好做。最后交了13发E才过,中间爆ll、memset超时。。赛后补了F。
只贴我写的三个题。
J: ZOJ 4067
题解:把所有0拿掉后贪心拿完前面的,然后再加上后面的最小值-1。改了三次在基佬紫帮助下才写对。
#include<cstdio> #include<iostream> #include<bitset> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #define mp make_pair #define pb push_back #define ll long long #define lc no[x].ch[0] #define rc no[x].ch[1] #define pa no[x].fa #define db double #define ls (x<<1) #define rs (x<<1|1) #define For(i,a,b) for(int i=a;i<=b;i++) #define Forr(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=1e5+7; ll a[maxn],tv; vector<ll>vec; int n,m; int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); int cnt=0; vec.clear(); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); if(a[i]==0)cnt++; else vec.push_back(a[i]); } m-=cnt; if(m<0){cout<<"Impossible\n";continue;} if(n-cnt==m){cout<<"Richman"<<"\n";continue;} ll ans=0; int pp=0; for(int i=0;i<(int)vec.size()&&pp<m;i++) { ans+=vec[i]; pp++; } ll minn=1e9+1; for(int i=m;i<(int)vec.size();i++) { minn=min(minn,vec[i]); } ans+=minn-1; cout<<ans<<"\n"; } }
E:ZOJ 4062
题解:二分答案,可以看出这个过程可以谈心,就是尽可能少的走回头路,check时优先满足当前这个格子的高度,然后一路做过去,要特判n-1的情况,因为这样如果n满足了就不需要走过去了。我写的偏复杂了,一开始记录每个点的高度,然后直接爆了ll,完全发现不了,写法太丑陋了,换了种写法继续TLE,,memset真棒。
#include<cstdio> #include<iostream> #include<bitset> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #define mp make_pair #define pb push_back #define ll long long #define lc no[x].ch[0] #define rc no[x].ch[1] #define pa no[x].fa #define db double #define ls (x<<1) #define rs (x<<1|1) #define For(i,a,b) for(int i=a;i<=b;i++) #define Forr(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=2e5+7; ll a[maxn],tv; ll n,m; ll cnt; ll pq[maxn]; bool check(ll x) { for(int i=1;i<=n;i++)pq[i]=0; ll fq=m; fq--; pq[1]++; for(int i=1;i<=n;i++) { if(fq<0)return false ; ll tmp=(x+a[i]-1)/a[i]; if((pq[i])>=tmp&&i<n) { fq--;pq[i+1]++;continue; } else if((pq[i])>=tmp&&i==n) { continue; } // if(x==5)cout<<pq[i]<<" "<<i<<" "<<fq<<endl; pq[i+1]=tmp-pq[i]; ll vq=tmp-pq[i]; if(i==n)fq-=(vq)*2; else if(i==n-1) { fq-=(vq*2); if(pq[n]>=(x+a[n]-1)/a[n])continue; else pq[n]++,fq--; } else pq[i+1]++,fq-=(vq*2+1); }// if(x==5)cout<<fq<<"\n"; if(fq>=0)return true; else return false; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } ll ans=0ll; ll l=1ll,r=1e18; while(l<=r) { ll mid=(l+r)>>1; if(check(mid))l=mid+1,ans=mid; else r=mid-1; //cout<<l<<" "<<r<<" "<<mid<<" "<<ans<<"\n"; } printf("%lld\n",ans); } }
F:ZOJ 4063
题解:当时现场赛的队伍说有很多构造题,于是我天真的觉得这应该是个构造题,然后发现自己无从下手,就中期怼E去了,然后晚上发现D不会做,就继续想,瞄了眼题解说打表找规律。然后打了20分钟的表成功打出,于是找规律,发现就是对于当前第i行,是以lowbit(i)*2的长度分段的,以上一行按照这个长度进行中心旋转得到的,然后什么时候不行呢,疯狂枚举发现,当m>=lowbit(n)时不成立。因此就打表预处理然后输出就好了。
打表代码:
#include<cstdio> #include<iostream> #include<bitset> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #define mp make_pair #define pb push_back #define ll long long #define lc no[x].ch[0] #define rc no[x].ch[1] #define pa no[x].fa #define db double #define ls (x<<1) #define rs (x<<1|1) #define For(i,a,b) for(int i=a;i<=b;i++) #define Forr(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=1e5+7; int a[200][200]; int vis[200][200]; int pan[200]; vector<int >vec[maxn]; int main() { memset(vis,0,sizeof(vis)); for(int i=1;i<=20;i++)a[0][i]=i,vis[i][i]=1; for(int i=1;i<=20;i++) { memset(pan,0,sizeof(pan)); for(int j=1;j<=20;j++) { if(!a[i][j]) for(int k=1;k<=20;k++) { if(!vis[j][k]&&j!=k&&!pan[k]) { int flag=0,fla=0; for(int pp=1;pp<i;pp++) { if(vis[j][a[pp][j]]&&vis[k][a[pp][k]]&&!vis[a[pp][k]][a[pp][j]]) { vis[j][k]=vis[a[pp][k]][a[pp][j]]=vis[k][j]=vis[a[pp][j]][a[pp][k]]=1; a[i][j]=k;a[i][k]=j;a[i][a[pp][k]]=a[pp][j];a[i][a[pp][j]]=a[pp][k];pan[k]=pan[j]=pan[a[pp][j]]=pan[a[pp][k]]=1; flag=1; break; } if(vis[j][a[pp][j]]&&vis[k][a[pp][k]])fla=1; } if(flag) {break;} if(!fla) { a[i][j]=k;a[i][k]=j;pan[k]=pan[j]=1;vis[j][k]=vis[k][j]=1;break; } } } } } for(int i=0;i<=15;i++) { for(int j=1;j<=15;j++) { cout<<a[i][j]<<(j==15?'\n':' '); } } }
AC代码:
#include<cstdio> #include<iostream> #include<bitset> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #define mp make_pair #define pb push_back #define ll long long #define lc no[x].ch[0] #define rc no[x].ch[1] #define pa no[x].fa #define db double #define ls x<<1 #define rs x<<1|1 #define For(i,a,b) for(int i=a;i<=b;i++) #define Forr(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=1005; int a[maxn][maxn]; int lowbit(int x){return x&(-x);} void cal() { for(int i=1;i<=1001;i++)a[0][i]=i; for(int i=1;i<=1001;i++) { int kk=lowbit(i);int pp=kk*2; for(int j=1;j<=1001;j+=pp) { for(int k=0;k<pp;k++) { a[i][j+k]=a[i-1][pp+j-k-1]; } } } /* for(int i=1;i<=20;i++) { for(int j=1;j<=20;j++) { cout<<a[i][j]<<(j==20?"\n":" "); } }*/ } int main() { cal(); int t; scanf("%d",&t); int n,m; while(t--) { scanf("%d%d",&n,&m); if(m>=lowbit(n)){cout<<"Impossible\n";continue;} for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) { cout<<a[i][j]<<(j==n?"\n":" "); } } } }