XVIII Open Cup named after E.V. Pankratiev. Grand Prix of SPb
A. Base $i - 1$ Notation
两个性质:
- $2=1100$
- $122=0$
利用这两条性质实现高精度加法即可。
时间复杂度$O(n)$。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; const int N = 6e6 + 10; const int inf = 1e9; int casenum, casei; char a[N], b[N]; int c[N]; int main() { freopen("base-i-1.in","r",stdin); freopen("base-i-1.out","w",stdout); while(~scanf("%s%s", a, b)) { int n = strlen(a); reverse(a, a + n); int m = strlen(b); reverse(b, b + m); //int n = 5e5; for(int i = 0; i < n; ++i)a[i] = '1'; a[n] = 0; //int m = 5e5; for(int i = 0; i < m; ++i)b[i] = '1'; b[m] = 0; int g = max(n, m); for(int i = 0; i < g; ++i) { int p = i / 2; c[i] = 0; if(i < n)c[i] += a[i] - 48; if(i < m)c[i] += b[i] - 48; } for(int i = 0; i < g; ++i) { int t=min(c[i]/2,min(c[i+1]/2,c[i+2])); c[i]-=t*2; c[i+1]-=t*2; c[i+2]-=t; int w = c[i] / 2; if(w) { c[i + 2] += w; c[i + 3] += w; g = max(g, i + 4); } c[i] %= 2; } while(g>1&&!c[g-1])g--; for(int i = g - 1; i >= 0; --i)printf("%d", c[i]); puts(""); } return 0; } /* */
B. Squaring a Bit
直接暴力枚举平方数即可通过,需要手写popcount。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; const int N = 3e5 + 10; typedef long long LL; LL n; int v[65555]; int popcount(LL x){ return v[x&65535]+v[x>>16&65535]+v[x>>32&65535]+v[x>>48]; } int main() { for(int i=1;i<65536;i++)v[i]=v[i>>1]+(i&1); freopen("bit-squares.in","r",stdin); freopen("bit-squares.out","w",stdout); while(~scanf("%lld", &n)) { LL len = 0; int one = 0; while(n) { ++len; one += n & 1; n /= 2; } LL bott = 1ll << (len - 1); int bot = sqrt(bott) + 0.99999999; LL topp = (1ll << len) - 1; int top = sqrt(min(topp, (LL)1e18)); //printf("%lld %lld\n", bott, topp); //printf("%d %d\n", bot, top); int ans = 0; LL val = (LL)bot * bot, add = bot * 2 + 1; int i=bot; for(;i+4<=top;i+=4){ if(popcount(val) == one)++ans; val += add, add += 2; if(popcount(val) == one)++ans; val += add, add += 2; if(popcount(val) == one)++ans; val += add, add += 2; if(popcount(val) == one)++ans; val += add, add += 2; } for(; i <= top; ++i, val += add, add += 2) { //printf("%d %lld\n", i, val); //val = (LL)i * i; if(popcount(val) == one)++ans; } printf("%d\n", ans); } return 0; } /* */
C. Chickens
状压DP求方案数。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; const int N = 3e5 + 10; const int inf = 1e9; int casenum, casei; int c[15], e[15]; int f[15][1 << 13]; int n; int main() { freopen("chickens.in","r",stdin); freopen("chickens.out","w",stdout); while(~scanf("%d", &n)) { for(int i = 0; i < n; ++i)scanf("%d", &c[i]); for(int i = 0; i < n; ++i)scanf("%d", &e[i]); memset(f, 0, sizeof(f)); f[0][0] = 1; int top = (1 << n) - 1; for(int i = 0; i < n; ++i) { for(int j = 0; j <= top; ++j)if(f[i][j]) { for(int k = 0; k < n; ++k)if((~j >> k & 1) && c[i] <= e[k]) { f[i + 1][j | 1 << k] += f[i][j]; } } } printf("%d\n", f[n][top]); } return 0; } /* */
D. Lights at a Crossing
对于每个观察,枚举两盏红灯,由剩余时间大的向小的连权值为差值的有向边,则最小周期为这个有向图的最小环。
时间复杂度$O(n^3+mn^2)$。
#include<cstdio> const int N=30,inf=10000000; int n,m,i,j,k,f[N][N],a[N],ans=inf;char s[99]; inline void up(int&x,int y){x>y?(x=y):0;} int main(){ scanf("%d%d",&n,&m); for(i=1;i<=n;i++)for(j=1;j<=n;j++)f[i][j]=inf; while(m--){ for(i=1;i<=n;i++){ scanf("%s",s); if(s[0]=='X')a[i]=-1;else sscanf(s,"%d",&a[i]); } for(i=1;i<=n;i++)if(~a[i])for(j=i+1;j<=n;j++)if(~a[j]){ if(a[i]<a[j])up(f[i][j],a[j]-a[i]); if(a[i]>a[j])up(f[j][i],a[i]-a[j]); } } for(k=1;k<=n;k++)for(i=1;i<=n;i++)for(j=1;j<=n;j++)up(f[i][j],f[i][k]+f[k][j]); for(i=1;i<=n;i++)up(ans,f[i][i]); if(ans==inf)ans=-1; printf("%d",ans); }
E. Decimal Form
法雷序列求两分数之间分母最小的分数。
时间复杂度$O(T\log w)$。
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef long long ll; typedef long double ld; typedef __int128 lll; typedef pair<lll,lll>P; lll n,r,a,b,c,d,t; int Case; ld goal; const int lim=1000000000; const ld eps=1e-15; lll gcd(lll a,lll b){return b?gcd(b,a%b):a;} P cal(lll a,lll b,lll c,lll d){ lll x=a/b+1; if(x*d<c)return P(x,1); if(!a)return P(1,d/c+1); if(a<=b&&c<=d){ P t=cal(d,c,b,a); swap(t.first,t.second); return t; } x=a/b; P t=cal(a-b*x,b,c-d*x,d); t.first+=t.second*x; return t; } void write(lll x){ if(x>=10)write(x/10); x%=10; printf("%d",(int)x); } //0.666666666666666667 int main(){ freopen("decimal-form.in","r",stdin); freopen("decimal-form.out","w",stdout); scanf("%d",&Case); while(Case--){ n=18; static char s[100]; scanf("%s",s); int len=strlen(s); r=0; for(int i=2;i<len;i++)r=r*10+s[i]-'0'; if(!r){ puts("0 1"); continue; } for(t=10;n--;t*=10); a=r*10-5,b=t; c=r*10+5,d=t; lll o=gcd(a,b); a/=o,b/=o; o=gcd(c,d); c/=o,d/=o; P p=cal(a,b,c,d); if(b<p.second)p=P(a,b); write(p.first); putchar(' '); write(p.second); puts(""); } }
F. Martian Maze
留坑。
G. Wet Mole
Floodfill求出所有水能灌到的点即可。
时间复杂度$O(nm)$。
#include<cstdio> const int N=1010; int n,m,i,j,flag;char a[N][N];bool v[N][N]; inline bool check(int x,int y){ if(x<1||x>n||y<1||y>m)return 0; if(a[x][y]=='#')return 0; return 1; } void dfs(int x,int y){ if(v[x][y])return; v[x][y]=1; if(check(x+1,y))dfs(x+1,y); else{ if(check(x,y-1))dfs(x,y-1); if(check(x,y+1))dfs(x,y+1); } } int main(){ freopen("mole.in","r",stdin); freopen("mole.out","w",stdout); scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%s",a[i]+1); for(i=1;i<=m;i++)if(a[1][i]=='.')dfs(1,i); for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(a[i][j]=='.'&&!v[i][j]){ if(!flag){ flag=1; a[i][j]='X'; } } if(flag){ puts("Yes"); for(i=1;i<=n;i++)puts(a[i]+1); }else puts("No"); }
H. Oddities
留坑。
I. Sorting on the Plane
将所有向量分成两类:在$1$号向量左侧和右侧的。然后分别排序即可。
时间复杂度$O(n\log n)$。
#include<cstdio> #include<algorithm> #include<vector> using namespace std; const int N=100010; int n,i,f[N],m,t; vector<int>q[2]; int ask(int x,int y){ printf("? %d %d\n",x,y); fflush(stdout); int t; scanf("%d",&t); return t; } bool cmp(int x,int y){return ask(x,y);} int main(){ scanf("%d",&n); if(n==1){ puts("! YES"); puts("1"); fflush(stdout); return 0; } for(i=2;i<=n;i++){ q[ask(1,i)].push_back(i); } for(i=0;i<2;i++)sort(q[i].begin(),q[i].end(),cmp); for(i=0;i<q[0].size();i++)f[++m]=q[0][i]; f[++m]=1; for(i=0;i<q[1].size();i++)f[++m]=q[1][i]; if(t=ask(f[1],f[m]))puts("! YES");else puts("! NO"); if(!t)printf("%d ",m); for(i=1;i<=m;i++)printf("%d ",f[i]); fflush(stdout); return 0; }
J. Center of List of Sums
二分求出上下界以及上下界的排名,然后将中间的数暴力取出即可。
时间复杂度$O(n\log n)$。
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=2000010; int n,m,i;ll a[N],b[N],q[N],L,R,down,up,cntdown,cntup; inline ll cal(ll lim){//<=lim int i=1,j=n; ll t=0; for(i=1;i<=n;i++){ while(j&&a[i]+b[j]>lim)j--; t+=j; } return t; } inline ll getkth(ll k){ ll l=0,r=2100000000,mid,t; while(l<=r){ mid=(l+r)>>1; if(cal(mid)>=k)r=(t=mid)-1;else l=mid+1; } return t; } void push(ll A,ll B){ int i,j=n,k=n; for(i=1;i<=n;i++){ while(j&&a[i]+b[j]>=A)j--; while(k&&a[i]+b[k]>B)k--; for(int o=j+1;o<=k;o++)q[++m]=a[i]+b[o]; } } int main(){ freopen("sums-center.in","r",stdin); freopen("sums-center.out","w",stdout); scanf("%d",&n); for(i=1;i<=n;i++)scanf("%lld",&a[i]); for(i=1;i<=n;i++)scanf("%lld",&b[i]); sort(a+1,a+n+1); sort(b+1,b+n+1); L=1LL*n*(n-1)/2+1; R=1LL*n*(n+1)/2; down=getkth(L); up=getkth(R); //printf("L=%lld R=%lld down=%lld up=%lld\n",L,R,down,up); if(down==up){ for(ll o=L;o<=R;o++)printf("%lld ",down); return 0; } cntdown=cal(down);//<=down cntup=cal(up-1);//<up //printf("cnt=%lld %lld\n",cntdown,cntup); push(down+1,up-1); for(ll o=L;o<=cntdown&&o<=R;o++)q[++m]=down; for(ll o=R;o>cntup&&o>=L;o--)q[++m]=up; sort(q+1,q+m+1); for(i=1;i<=m;i++)printf("%lld ",q[i]); }
K. Cookies
将每个串排序,然后直接DP求出最长链即可。
#include<cstdio> #include<string> #include<algorithm> #include<map> #include<iostream> using namespace std; const int N=180000; int n,m,i; int len[N]; int f[N],g[N]; string name[N],show[N],need[N]; map<string,int>pos; string q[N]; int dp(int x){ if(!x)return 0; if(f[x])return f[x]; int A=f[x],B=0; for(int i=0;i<name[x].size();i++){ string now=name[x]; now.erase(i,1); int o=pos[now]; if(!o)continue; int t=dp(o); if(t>A)A=t,B=o; } f[x]=A+1,g[x]=B; return f[x]; } int main(){ freopen("word-chains.in","r",stdin); freopen("word-chains.out","w",stdout); cin>>n;//n=10000 for(i=0;i<n;i++)cin>>need[i]; cin>>m;//173554 m++; name[1]=""; show[1]="."; for(i=2;i<=m;i++){ cin>>name[i]; show[i]=name[i]; } for(i=1;i<=m;i++){ sort(name[i].begin(),name[i].end()); pos[name[i]]=i;//sorted len[i]=name[i].size(); } for(i=0;i<n;i++){ string now=need[i]; sort(now.begin(),now.end()); int x=pos[now]; dp(x); int cnt=0; while(x){ q[++cnt]=show[x]; x=g[x]; } q[1]=need[i]; cout<<cnt<<endl; for(int j=1;j<=cnt;j++){ cout<<q[j]; if(j<cnt)cout<<" -> ";else cout<<endl; } } } /* 4 university open cup cookie 17 university intrusive neuritis unities seniti nisei sine sei e es one ne open cup up p cookie */
L. Xor-fair Division
若所有数异或和非$0$,则答案为$0$,否则答案为$2^n-2$。
#include<cstdio> typedef long long ll; int n;long long ans,sum,x; int main(){ freopen("xorseq.in","r",stdin); freopen("xorseq.out","w",stdout); scanf("%d",&n); ans=1LL<<n; while(n--){ scanf("%lld",&x); sum^=x; } if(sum)ans=0; else if(n==1)ans=0; else ans-=2; printf("%lld",ans); }