寒假训练2021-1-21

重庆还是挺冷的
Good Bye 2020 训练
演了一把 直接爆零好家伙
在这里插入图片描述
A题 Bovine Dilemma
没啥好说的,意思就是给你一个点(0,1) 剩下的n个点全在x轴上面,问你能够组成的不同面积的三角形有多少个 - - 既然高固定了,那么直接求一次不同的底有多少个就好了
B. Last minute enhancements
给了我们n个数,我们可以对一个数操作一次,要么删除它,要么让它+1,问最后有最多多少个不同的数。直接模拟吧
C. Canine poetry
大概意思是允许我们替换任意的字符,问最少多少次可以使得整个字符串不存在任何回文子串。首先考虑下大的回文串一定是小的回文串组成,最小回文串要么是长度为2,要么是长度为3的,那么我们直接破坏最小回文就OK ,枚举一次
D. 13th Labour of Heracles
根据度,放入一个容器,然后从大到小往先前的权值和加就OK
E. Apollo versus Pan
在这里插入图片描述
一个简单位运算的题吧,上面的式子显然可以变化一下
ΣiΣj (xi&xj)*Σk(xj|xk) 因为跟xj 挂钩 ,所以不妨变为ΣjΣi (xi&xj)*Σk(xj|xk)
枚举xj , 每次处理60位,就OK了。`

 #include<bits/stdc++.h>
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define int long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
 using namespace std;
 ll gcd(ll a,ll b){
    
    if(a<0)a=-a;if(b<0)b=-b;return b==0?a:gcd(b,a%b);}
template<typename T>void read(T &res){
    
    bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
ll lcm(ll a,ll b){
    
    return a*b/gcd(a,b);}
ll qp(ll a,ll b,ll mod){
    
    ll ans=1;if(b==0){
    
    return ans%mod;}while(b){
    
    if(b%2==1){
    
    b--;ans=ans*a%mod;}a=a*a%mod;b=b/2;}return ans%mod;}//快速幂%
ll qpn(ll a,ll b, ll p){
    
    ll ans = 1;a%=p;while(b){
    
    if(b&1){
    
    ans = (ans*a)%p;--b;}a =(a*a)%p;b >>= 1;}return ans%p;}//逆元   (分子*qp(分母,mod-2,mod))%mod;
ll a[555555];
ll cnt[65];
ll pre[65];
signed main(){
    
    
    ll t;
    read(t);
    for(int i=0;i<=60;i++){
    
    
        pre[i]=qp(2,i,mods);
    }
    while(t--){
    
    
    ll n;
    read(n);
    memset(cnt,0,sizeof(cnt));
    for(int i=1;i<=n;i++){
    
    
        read(a[i]);
        for(int j=0;j<60;j++){
    
    
         if(a[i]>>j&1){
    
    
            cnt[j]++; // 第j位有1
         }

        }
    }
    ll sum=0;
    for(int i=1;i<=n;i++){
    
    
    ll rnm=0;
    ll cnm=0;
    for(int j=0;j<60;j++){
    
    
    if(a[i]>>j&1){
    
    
    rnm=(rnm+pre[j]%mods*cnt[j]%mods)%mods;
    cnm=(cnm+pre[j]%mods*n%mods)%mods ;
    }
    else{
    
    
    // 如果此位无1
    //& =0
    cnm=(cnm+pre[j]%mods*cnt[j]%mods)%mods;
    }
    }
     sum=(sum+cnm%mods*rnm%mods)%mods;
    }
    printf("%lld\n",sum%mods);
    }
}

F题 待补 - - 下午刷专题

晚上搞了场context 来的有点晚 - -
在这里插入图片描述
A题直接模拟下就OK了 签到题

char s[111111];
char b[111111];
char op[10];
ll c[1111111];
ll cnt=0;
signed main(){
    
    
 scanf("%s%s%s",s+1,b+1,op+1);
 ll n=strlen(s+1);
 ll m=strlen(b+1);

 ll rnm=max(n,m)-min(n,m);

 if(n>m){
    
    
 for(int i=1;i<=rnm;i++){
    
    
 ll ok=s[i]-'0';
 if(op[1]=='a'){
    
    
 // printf("%lld",ok&0);
 c[++cnt]=ok&0;
 }
 if(op[1]=='o'){
    
    
c[++cnt]=ok|0;
 }
 if(op[1]=='x'){
    
    
 c[++cnt]=ok^0;
 }
 }
  for(int i=rnm+1,j=1;i<=n;i++,j++){
    
    
 ll ok=s[i]-'0';
 ll okk=b[j]-'0';
if(op[1]=='a'){
    
    
 c[++cnt]=ok&okk;
 }
 if(op[1]=='o'){
    
    
    c[++cnt]=ok|okk;
 }
 if(op[1]=='x'){
    
    
    c[++cnt]=ok^okk;
 }
 }

 }

 if(n==m){
    
    
    for(int i=1;i<=n;i++){
    
    
         ll ok=s[i]-'0';
 ll okk=b[i]-'0';
if(op[1]=='a'){
    
    
 c[++cnt]=ok&okk;
 }
 if(op[1]=='o'){
    
    
    c[++cnt]=ok|okk;
 }
 if(op[1]=='x'){
    
    
    c[++cnt]=ok^okk;
 }
    }
 }
 if(n<m){
    
    
 for(int i=1;i<=rnm;i++){
    
    
 ll ok=b[i]-'0';
 if(op[1]=='a'){
    
    
 // printf("%lld",ok&0);
 c[++cnt]=ok&0;
 }
 if(op[1]=='o'){
    
    
c[++cnt]=ok|0;
 }
 if(op[1]=='x'){
    
    
 c[++cnt]=ok^0;
 }
 }
  for(int i=rnm+1,j=1;i<=m;i++,j++){
    
    
 ll ok=b[i]-'0';
 ll okk=s[j]-'0';
if(op[1]=='a'){
    
    
 c[++cnt]=ok&okk;
 }
 if(op[1]=='o'){
    
    
    c[++cnt]=ok|okk;
 }
 if(op[1]=='x'){
    
    
    c[++cnt]=ok^okk;
 }
 }

 }
 ll f=0;
 for(int i=1;i<=cnt;i++){
    
    
  if(f==0&&c[i]==0){
    
    continue;}
  f++;
  printf("%lld",c[i]);
 }
}

在这里插入图片描述
B题一个记忆化搜索搞定 注意点边缘细节


int ans;
int x,y,fx,fy,ax,ay,st=1e9;
int f[25][25];
int dx[4]= {
    
    0,0,1,-1};
int dy[4]= {
    
    1,-1,0,0};

ll dis(ll a,ll b,ll c,ll d)
{
    
    
    return abs(a-c)+abs(b-d);
}

 bool check(int x,int y)
{
    
    
    return (x==1|| x==19||y==1 || y==19) && (x>=1 && x<=19 && y>=1 && y<=19);
}

bool canget(int tx,int ty)
{
    
    
    return tx==fx || ty==fy;
}
void dfs(int lx,int ly,int sum)
{
    
    
    ll nx,ny;
    if (sum>=f[lx][ly]){
    
    return ;}

    f[lx][ly]=sum;
    if (canget(lx,ly) && dis(lx,ly,fx,fy)<ans)
        ans=dis(x,y,fx,fy),st=sum+dis(x,y,fx,fy);
    if (canget(lx,ly) && dis(lx,ly,fx,fy)==ans)
        st=min(st,st=sum+dis(x,y,fx,fy));
    for (int i=0; i<4; ++i)
    {
    
    
        nx=lx+dx[i];
        ny=ly+dy[i];
        if (check(nx,ny)==false)
            continue;
        dfs(nx,ny,sum+1);
    }
    return;
}
signed main()
{
    
    
    memset(f,inf,sizeof(f));
   read(x);
   read(y);
   read(fx);
   read(fy);
    dfs(x,y,0);
printf("%lld\n",f[fx][fy]);

    return 0;
}

在这里插入图片描述
因为冠军只跟接下来一轮的排名挂钩 我们先对之前的得分排个序 从大到小,前面的得分越高,我们现在给它分配越低的分数,对于其他前面分数不高的选手就有机会取到冠军,记录pre[i] 表示1–i 区间的最大值,suf[i] 表示n–i区间的最大值,现在枚举a[i] 令它为第一名,也就是a[i]+n 那么如果对于前缀pre[i] 满足 a[i]+n>=pre[i] 并且 a[i]+n>=suf[i]-1 (因为后面的区间分配了一个n,现在n并不在后面的区间了) 那么说明这个人可以成为冠军

const int ma=3e5+7;
ll pre[ma];
ll suf[ma];
ll a[ma];
ll sum[ma];
bool cmp(ll x,ll y){
    
    
return x>y;
}
signed main(){
    
    
  ll n;
  read(n);
  for(int i=1;i<=n;i++){
    
    
    read(a[i]);
  }
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
    
    
sum[i]=i+a[i]; // ai>=ai-1  +1
pre[i]=max(pre[i-1],sum[i]);
}
for(int i=n;i>=1;i--){
    
    
  suf[i]=max(suf[i+1],sum[i]);
}
ll ans=0;
for(int i=1;i<=n;i++){
    
    
  if(a[i]+n>=pre[i]&&a[i]+n>=suf[i]-1){
    
    
    ans++;//n 已经被拿了
  }
}
printf("%lld",ans);

}

在这里插入图片描述
n 1e5 联想到了昨天写过的那个单调队列+dp 这个题想了很久 ,正向我实在是推不走, 于是逆向dp
记dp[i][0/1] 表示在n–i 这个区间内 (0)先手 (1)后手的最佳情况
转移方程见代码吧 每次要控制在m的区间内


const int maxn=1e5+10;
ll a[maxn],dp[maxn][3];
ll que[maxn],pue[maxn];
signed main(){
    
    
   ll n,m;
    read(n);
    read(m);
    for(int i=1; i<=n; i++)
    {
    
    
        read(a[i]);
    }
    que[1]=n;
    pue[1]=n;
   ll head=1;
   ll tail=1;
   ll head_=1;
   ll tail_=1;
    for(int i=n; i>=1; i--)
    {
    
    
        while(head<=tail&&dp[que[tail]+1][1]+a[que[tail]]<=dp[i+1][1]+a[i]) // 上个状态  n--  i+1  我的最优
            tail--;  //否则出去
        que[++tail]=i;
        while(head_<=tail_&&dp[pue[tail_]+1][0]-a[pue[tail_]]>=dp[i+1][0]-a[i])  //同理
            tail_--;
        pue[++tail_]=i;
        while(head<=tail&&que[head]>=i+m)
            head++;
        while(head_<=tail_&&pue[head_]>=i+m)
            head_++;
        dp[i][0]=dp[que[head]+1][1]+a[que[head]];
        dp[i][1]=dp[pue[head_]+1][0]-a[pue[head_]];
    }
    printf("%lld\n%lld",dp[1][0],dp[1][1]);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45948940/article/details/112934074