https://ac.nowcoder.com/acm/contest/16520#question
A★★比赛新机制★★
环形取数,取n个 可以正取也可以逆取,第一个取的贡献n次,第二个n-1,第n个1次。
长的很像前缀和,然后递推一下,每次算上新的,利用前缀和改一下。
逆取直接sum*(n+1)-正取就好
int a[N],sum[N],n; void solve(){ cin>>n; int m=2*n,mm=3*n; for(int i=1;i<=n;++i){ cin>>a[i]; a[i+n]=a[i];a[i+2*n]=a[i]; } for(int i=1;i<=mm;++i){ sum[i]=sum[i-1]+a[i]; } int ans=inf,now=0,tmp=n; for(int i=n+1;i>=2;--i){ now=now+a[i]*tmp;tmp--; } //cout<<"=="<<now<<endl; ans=min(ans,now); ans=min(ans,(sum[n+1]-sum[1])*(n+1)-now); for(int i=n+2;i<=m;++i){ now=now+a[i]*n; now=now-(sum[i-1]-sum[i-n-1]); ans=min(ans,now); ans=min(ans,(sum[i]-sum[i-n])*(n+1)-now); //cout<<"=="<<now<<endl; } cout<<ans<<endl; }
★★生命的游戏★★
很明显是模拟,然后模拟就好,注意下确定一个周期是跟初始状态比较的
如果一个死亡的的细胞周围恰好有 333 个活的细胞,那么下一个回合时,这个细胞的状态将转为“生”
如果一个存活的的细胞周围活细胞的数量大于 333 或小于 222,那么下一个回合时,这个细胞的状态将转为“死”
其他情况下,细胞的存活状态不变
const int N= 1e2+7; int a[N][N][N],ans,n,k; int dd(int x,int y){ int f=1; for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ if(a[i][j][x]!=a[i][j][y]){ f=0;break; } } } return f; } int pd(int i,int j,int now){//死了判活 int cnt=0; int l=j-1,r=j+1,up=i-1,dw=i+1; if(l==0)l=n; if(r==n+1)r=1; if(up==0)up=n; if(dw==n+1) dw=1; if(a[i][l][now]==1) cnt++; if(a[i][r][now]==1) cnt++; if(a[up][l][now]==1) cnt++; if(a[up][j][now]==1) cnt++; if(a[up][r][now]==1) cnt++; if(a[dw][l][now]==1) cnt++; if(a[dw][j][now]==1) cnt++; if(a[dw][r][now]==1) cnt++; if(cnt==3) return 1; return 0; } int pd2(int i,int j,int now){//活了判死 int cnt=0; int l=j-1,r=j+1,up=i-1,dw=i+1; if(l==0)l=n; if(r==n+1)r=1; if(up==0)up=n; if(dw==n+1) dw=1; if(a[i][l][now]==1) cnt++; if(a[i][r][now]==1) cnt++; if(a[up][l][now]==1) cnt++; if(a[up][j][now]==1) cnt++; if(a[up][r][now]==1) cnt++; if(a[dw][l][now]==1) cnt++; if(a[dw][j][now]==1) cnt++; if(a[dw][r][now]==1) cnt++; if(cnt>3||cnt<2) return 1; return 0; } void solve(){ int flag=0; cin>>n>>k; for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ cin>>a[i][j][0]; } } for(int t=0;t<=k;++t){ int now=t,nxt=1+t; for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ if(a[i][j][now]==0){//死了判活 if(pd(i,j,now)==1){ a[i][j][nxt]=1;//修改到下一个回合 } else{ a[i][j][nxt]=a[i][j][now]; } } else{//活了判死 if(pd2(i,j,now)==1){ a[i][j][nxt]=0; } else{ a[i][j][nxt]=a[i][j][now]; } } } } //print(now); if(dd(0,t)&&t!=0){ flag=1; ans=t; break; } } if(flag==1){ cout<<"YES "; cout<<ans<<endl; } else cout<<"NO "; }
★★飞马分隔符★★
对字符串划分若干部分,使得每一部分都不包含子序列FeiMa。而每次划分都需要一个“分隔符”,要求最少个分割符。
出现了一个子序列就划分,就这样。
void solve(){ int f=0,cnt=0; cin>>n; cin>>s+1; for(int i=1;i<=n;++i){ if(f==0&&s[i]=='F')f=1; else if(f==1&&s[i]=='e')f=2; else if(f==2&&s[i]=='i')f=3; else if(f==3&&s[i]=='M')f=4; else if(f==4&&s[i]=='a')f=5; if(f==5){ cnt++;f=0; } } cout<<cnt<<endl; }
★★温暖的力量★★
把给定的数划分为x份质数 要求x>1 ,然后让x最多
很明显用2和3去分就好。
void solve(){ cin>>n; if(n<=3) cout<<"-1"<<endl; else cout<<n/2<<endl; }
★★翻滚吧硬币★★
给三个圆的半径,求最小的,一个圆切另外两个圆然后绕一周回到该位置,最少的圈数
怎么说呢,是滚动不是滑动,滑动类似外边插一个时针
滚动要贴合,实际上要以圆心为路径的计算。
const int N= 2e6+7; double n,a,c,b; double did(double ra,double rb,double rc){ double Bac=ra+rc; double Bab=ra+rb; double Bbc=rb+rc; double zhou=2*PI*rc; double Jcab=acos((Bac*Bac+Bab*Bab-Bbc*Bbc)/(2*Bac*Bab))*(180.0)/PI; Jcab=360.0-2*Jcab; double Jcba=acos((Bab*Bab+Bbc*Bbc-Bac*Bac)/(2*Bab*Bbc))*(180.0)/PI; Jcba=360.0-2*Jcba; double sum=Jcab*PI*Bac/180.0+Jcba*PI*Bbc/180.0; return sum/zhou; } void solve(){ scanf("%lf%lf%lf",&a,&b,&c); double ans=did(a,b,c); ans=min(ans,did(a,c,b)); ans=min(ans,did(b,c,a)); printf("%.10lf ",ans); }
★★序列大团结★★
对于对于给定序列,问满足以下条件的非空连续子序列E的个数
const int p= 998244353; ull n,k,ans,now,hs,x; map<ull,int>num; map<int,int>s;//前i个数中 值v的出现次数 模k 的余数 inline ull ksm(ull x,ull k){ ull res=1; for(;k;k>>=1,x=x*x) if(k&1) res=res*x; return res; } void solve(){ cin>>n>>k; num.clear(); s.clear(); ans=now=0; num[0]=1; for(int i=1;i<=n;++i){ cin>>x; if(x%k){ hs=ksm(p,x);//hs记录当前值对哈希的影响 now-= hs*s[x];//去除原先值的影响 s[x]=(s[x]+1)%k; now+=hs*s[x];//如果次数k倍 不还原 } ans+=num[now];//now为记录前i的总情况的哈希,次数加上 num[now]++; } cout<<ans<<endl; }
★★平形四边行★★
正常的平行四边形:两组对边分别平行且相等的四边形是平行四边形
本题目的:两组对边分别相等的图形称为“平形四边行”,即使四个顶点可能共线甚至重合。
考虑重合和共线的情况,发现
四个点能形成"平形四边行”的充要条件是,存在一种方案,将四个点均分为两组,每组的两个点形成一条线段,这两条线段的中点重合。
注意到桶的大小只有4000 x 4000,即第4000 x 4000++1个点落下时,一定存在重合的中点,从而构成—组解。另外,桶不可能被完全填满,因此复杂度远远小于预期。
抽屉定理。然后避免交集出现。
int n,x[N],y[N]; pair<int,int>v[4005][4005]; void solve(){ cin>>n; for(int i=1;i<=n;++i){ cin>>x[i]>>y[i]; for(int j=1;j<i;++j){ int xx=x[i]+x[j]+2000; int yy=y[i]+y[j]+2000; if(i==v[xx][yy].first||i==v[xx][yy].second)continue;//避免A与重合的BD三点构成 if(j==v[xx][yy].first||j==v[xx][yy].second)continue; if(v[xx][yy].first){ cout<<"YES "; cout<<i<<" "<<j<<" "<<v[xx][yy].first<<" "<<v[xx][yy].second<<endl; return ; } v[xx][yy]=make_pair(i,j); } } cout<<"NO "; }