本蒟蒻这次只过了三题 赛后学习了一下出题人巨佬的标码(码风比我好多了 贴的代码有些是仿出题人)
现在将自己的理解写下来与大家分享

A
这个题一分析就是每个数字都会与所有数字&一下 (a&a=a)
&字操作是二进制同位都为一才为一 这时解法就变成统计每个二进制位上1的次数

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include<bits/stdc++.h> #define ll  long long using namespace std; const ll maxn = 1e5; const ll maxm =  30 ; ll res; ll arr[maxn +  5 ], n, cnt[maxm +  5 ];   int main() {      scanf( "%d" , &n);      for ( int i =  1 ; i <= n; ++i)scanf( "%d" , &arr[i]);      for ( int i =  1 ; i <= n; ++i)          for ( int j =  0 ; j <  30 ; ++j)              if (arr[i] & ( 1 << j))cnt[j] +=  1 ; ///各位上1的个数      for ( int i =  0 ; i <  30 ; ++i)res +=  cnt[i] * cnt[i] * ( 1 << i);      printf( "%lld\n" , res);      return 0 ; }

B
简单的n2枚举 分析一下可以知道每条边都用了n-2次

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <bits/stdc++.h> #define ll  long long using namespace std; ll n,ans; ll mod= 998244353 ; struct P {      ll x,y; }a[ 110 ]; ll len(P m,P n) {      return abs(m.x-n.x)+abs(m.y-n.y); } int main() {      scanf( "%lld" ,&n);      for ( int i= 1 ;i<=n;++i)scanf( "%lld%lld" ,&a[i].x,&a[i].y);      for ( int i= 1 ;i<=n;++i)      {          for ( int j=i+ 1 ;j<=n;++j)          {             ans+=(len(a[i],a[j])*(n- 2 ))%mod;          }      }      cout<<ans%mod<<endl;      return 0 ; }

C
这是一个比较基础的dp方程的进阶 从n个物品中选k个
dp[i][j]=dp[i-1][j]+dp[i-1][j-1]
i表示到第几个字符了 j是用了几个字符
dp[i-1][j]是不用这个新加的 dp[i-1][j-1]是用这个新加的
这题的关键点是我们这样计算重复了多少字符(本质不同的解释)
其实仔细一想 我们重复计算就是相当于把 输出前面出现的那个符号在那里又多算了一次
多了哪一部分 这个重复符号上次出现的位置的dp值

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include<bits/stdc++.h> #define ll  long long using namespace std;   const ll maxn =  1000 ; const ll mod = 1e9 +  7 ;   ll dp[maxn +  5 ][maxn +  5 ];   ll n, k, pre[maxn +  5 ]; ///pre记录上次同一个字符的出现位置 char s[maxn +  5 ];   int main() {      scanf( "%d %d" , &n, &k);      scanf( "%s" , s +  1 );      dp[ 0 ][ 0 ] =  1 ; ///n中选0个为1种情况      for ( int i =  1 ; i <= n; ++i) {          dp[i][ 0 ] =  1 ;          for ( int j =  1 ; j <= i; ++j) {              dp[i][j] = dp[i -  1 ][j] + dp[i -  1 ][j -  1 ];              if (pre[s[i] -  'a' ])dp[i][j] -= dp[pre[s[i] -  'a' ] -  1 ][j -  1 ];              dp[i][j] %= mod;          }          pre[s[i] -  'a' ] = i;      }      ll res = dp[n][k];      if (res <  0 )res += mod;      printf( "%lld\n" , res);      return 0 ; }

D
这题由于蒟蒻(我)追求梦想用n2枚举过了 但赛后还是写了一下正解方程(n枚举应该可以过)
写这题你需要一个 扩展欧几里得模板(能判断是否有整数解) 然后枚举一个数就把题目变成了一个模板题了 前面是n2枚举 后面大概是正解

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <bits/stdc++.h> #define ll  long long using namespace std; ll a,b,c,k,minl; int main() {      cin>>a>>b>>c>>k;      minl=min(a,min(b,c));      ll s=k/minl;      for ( int i= 1 ;i<=s;++i)      {          for ( int j= 1 ;j<=s;++j)          {              ll z1=k-a*i-b*j;              ll z2=k-b*i-c*j;              ll z3=k-a*i-c*j;              if (z1%c== 0 ){cout<<i<< " " <<j<< " " <<z1/c; return 0 ;}              if (z2%a== 0 ){cout<<z2/a<< " " <<i<< " " <<j; return 0 ;}              if (z3%b== 0 ){cout<<i<< " " <<z3/b<< " " <<j; return 0 ;}          }      }      return 0 ; }   #include <bits/stdc++.h> #define ll  long long using namespace std; ll a,b,c,k; void exgcd(ll a,ll b,ll&x,ll&y) {      if (b== 0 )      {          x= 1 ;          y= 0 ;          return ;      }      exgcd(b,a%b,x,y);      ll t=x;      x=y;      y=t-(a/b)*y; }   ll gcd(ll a,ll b){      return b== 0 ?a:gcd(b,a%b); }   int main() {      scanf( "%lld%lld%lld%lld" ,&a,&b,&c,&k);      for (ll i= 0 ;i<=k/c;i++){          ll d=k-i*c;          ll x,y;          exgcd(a,b,x,y);          ll e=gcd(a,b);          if (d%e!= 0 continue ; ///有无解          ll n=d/e;          ll m=b/e;          x*=n;y*=n;          x=(x%m+m)%m;          y=(d-x*a)/b; ///有无整数解          if (x>= 0 &&y>= 0 ){              printf( "%lld %lld %lld" ,x,y,i);              return 0 ;          }      }      return 0 ;   }

F
这题作为正在学习计算几何的蒟蒻(我) 那肯定是要学习的
做这题的关键是要注意画图才能理解 代码里大部分有注释

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 #include<bits/stdc++.h> #define lowbit(x) x&(-x) #define ll  long long using namespace std; typedef pair< int , int > pii;   const int maxn=1e5+ 7 ; const int pi=acos(- 1.0 ); const double eps=1e- 9 ;   int read() ///快读 {      int x= 0 ,f= 1 ; char s=getchar();      for ( ;!isdigit(s);s== '-' && (f=- 1 ),s=getchar());      for ( ;isdigit(s);x=x* 10 +s- 48 ,s=getchar());      return x*f; }   struct point {      int x,y,tag;      point( ) { x=y=tag= 0 ; }      point( ll _x,ll _y )      {          x=_x,y=_y;      }      bool operator==(  const point& rhs )  const {          return x==rhs.x && y==rhs.y;      }      point operator -( const point &rhs )  const {          return point(x-rhs.x,y-rhs.y);      }      point operator+(  const point &rhs )  const {          return point(x+rhs.x,y+rhs.y);      }      ll operator * (  const point &rhs )  const /// 叉积          return 1ll*x*rhs.y-1ll*y*rhs.x;      }      ll dot(  const point &rhs )  const /// 点积          return 1ll*x+rhs.x+1ll*y*rhs.y;      }      void get() { x=read(),y=read(); } }O,p[maxn],w1[maxn],w2[maxn],A,B; int n,m1,m2;   inline bool cmpA( point a,point b ) {  return (a-A)*(b-A)> 0 ; } inline bool cmpB( point a,point b ) {  return (a-B)*(b-B)> 0 ; }   int c[maxn]; ll ans= 0 ; void add(  int x ) {  while ( x<n ) c[x]++,x+=lowbit(x); } int query(  int x , int tt= 0 ) {  while ( x ) tt+=c[x],x-=lowbit(x); return tt;}   void solve( point *t, int m ) {      sort(t+ 1 ,t+ 1 +m,cmpA); ///以A点极角排序      ans+=(1ll*m*(m- 1 ))>> 1 ; ///先假设所有点对都能与线段相交      for int i= 1 ;i<=m;i++ ) t[i].tag=i;      sort(t+ 1 ,t+m+ 1 ,cmpB); ///以B点极角排序      memset(c, 0 ,sizeof(c));      for int i= 1 ;i<=m;i++ ) ///减去不能与线段相交的点对      {          ///这里假设线段点为P、Q  选出来的点对为 A、B  在画图过程中发现          ///选出来的能交的点对        B点要以P排序在A前面而且以Q排序也要在A前面          ///不是就减去   以树状数组解决这个区间问题          ans-=query(t[i].tag);          add(t[i].tag);      } }   int main() {      n=read(),A.get(),B.get();      for int i= 1 ;i<=n;i++ ) p[i].get();      for int i= 1 ;i<=n;i++ )      {          if ( (A-p[i])*(B-p[i])>0ll ) w1[++m1]=p[i]; ///利用叉积把点分为线段上下两部分          else w2[++m2]=p[i];      }      solve(w1,m1); ///第一种情况  两个点在同一侧      solve(w2,m2);        ans+=1ll*m1*m2; ///第二种情况 两个点在不同侧  还是一样先假设所有点对都能与线段相交        sort(w1+ 1 ,w1+m1+ 1 ,cmpA); ///一样 以A点极角排序      sort(w2+ 1 ,w2+m2+ 1 ,cmpA);      for int i= 1 ,bas= 1 ;i<=m1;i++ ) ///减去不能与线段相交的点对      {          ///i 上侧   bas 下侧          ///画图分析          while ( bas<=m2 && (w1[i]-A)*(w2[bas]-A)> 0 ) ++bas; ///叉积判断          ans-=bas- 1 ;      }        sort(w1+ 1 ,w1+m1+ 1 ,cmpB); ///以B点极角排序      sort(w2+ 1 ,w2+m2+ 1 ,cmpB);      for int i= 1 ,bas= 1 ;i<=m2;i++ )      {          ///一样          while ( bas<=m1 && (w2[i]-B)*(w1[bas]-B)> 0 ) ++bas;          ans-=bas- 1 ;      }      printf( "%lld\n" ,ans);      return 0 ; }

e题的题解可能在我大佬队友写完后贴出来(这个方向我是真不会).....
看到最后的彩蛋 推荐纯音乐 Like Sunday,Like Rain ^-^

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄