【简单题】敲响警钟!!!

【简单题】

真的是醉了
对于一道题 要分清什么是重要的 什么是不重要的 只关注重要的 没有思路就不要想复杂
一定不要把结论想当然!一定要注意讨论所有情况!!!

举手赢棋easy

https://ac.nowcoder.com/acm/contest/101196/C

错因

简单考虑了必救局答案为1
没有考虑必救局前面有0也可以直接救

代码

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=1e5+10;
int n;
string s;
int win[N],lose[N];
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>n;
      cin>>s;
      int ans=0;
      for(int i=0;i<n;i++){
            if(s[i]=='0'){
                  win[i+1]=win[i];
                  lose[i+1]=lose[i]+1;
            }
            else{
                  lose[i+1]=lose[i];
                  win[i+1]=win[i]+1;
            }
      }
      bool is_ok=true;
      //救不回来
      for(int i=1;i<=n;i++){
            if(s[i-1]=='0'){
                  if(win[i]+2<lose[i]){
                        is_ok=false;
                        break;
                  }
            }
            else if(s[i-1]=='1'){
                  if(win[i]+1<lose[i]){
                        is_ok=false;
                        break;
                  }
            }
      }
      if(is_ok){
            /*
            (没救了)
            如何做到方案数>1且<n?->救命场前面的0都可以举手!!!
            */
            int pos=-1;
            for(int i=1;i<=n;i++){
                  if(win[i]<lose[i]){
                        pos=i;
                        break;
                  }
            }
            if(pos==-1) ans=n;
            else ans=lose[pos];
      }
      cout<<ans;
      return 0;
}

加法入门

https://ac.nowcoder.com/acm/contest/101921/C

错因

只考虑到同层情况 没考虑到隔一层也有可以满足的情况
image

代码

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int t;
ll n,l,r;
ll check(ll x){
      ll ans=x*(x+1)/2;
      return ans;
}
void solve(){
      //只有修改同一行才能平衡
      cin>>n>>l>>r;
      //分别二分查找在哪一行?
      ll le=1,ri=n+1;
      while(le<ri){
            ll mid=(le+ri)/2;
            if(check(mid)>=l) ri=mid;
            else le=mid+1;
      }
      ll ans1=ri;
      le=1,ri=n+1;
      while(le<ri){
            ll mid=(le+ri)/2;
            if(check(mid)>=r) ri=mid;
            else le=mid+1;
      }
      ll ans2=ri;
      //提取层数
      if(ans1==ans2) cout<<"Yes"<<endl;
      else if((ans1+1)==ans2){
            //打表得出结论
            ll tmp1=check(ans1);
            ll tmp2=check(ans2)-(ans2-1);
            ll temp1=tmp1-l+1;
            ll temp2=r-tmp2+1;
            if((temp1+temp2)<=ans1) cout<<"Yes"<<endl;
            else cout<<"No"<<endl;
      }
      else cout<<"No"<<endl;
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--) solve();
      return 0;
}

Was there an Array?

https://codeforces.com/contest/2069/problem/A

错因

直接构造的思路要再简单粗暴一点!

AC代码

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=110;
int t;
int n;
int b[N];
int c[N];
void solve(){
      cin>>n;
      memset(c,-1,sizeof c);
      memset(b,-1,sizeof b);
      for(int i=2;i<=n-1;i++) cin>>b[i];
      /*【构造思路】
      从左到右构造,则显然i+1个数一定不会被填过
      (1)该数的b为1:
          - 如果该数被填过:
                  如果该数和上一个数不一样 就直接判-1
                  如果该数和上一个数一样 则下一个也要变成一样
          - 如果该数没有被填过:
                  该数和上一个数一样 下一个数也和该数一样
      (2)该数的b为0:
          - 如果该数被填过:
                  如果该数和上一个数一样 那么下一个数一定要不一样(+1)
                  如果该数和上一个数不一样 下一个数不填(出错点!) 按照下一个数的性质再填(反正最后都要被填)
          - 如果该数没有被填过:
                  (直接粗暴构造)和上一个数不同 直接+1
      */
      c[1]=1;
      bool is_ok=true;
      for(int i=2;i<=n-1;i++){
            if(b[i]==1){
                  if(c[i]!=-1){//被填过
                        if(c[i-1]!=c[i]){
                              is_ok=false;
                              break;
                        }
                        else{
                              c[i+1]=c[i];
                        }
                  }
                  else{//没被填过
                        c[i]=c[i-1];
                        c[i+1]=c[i];
                  }
            }
            else if(b[i]==0){
                  if(c[i]!=-1){//被填过
                        if(c[i-1]==c[i]) c[i+1]=c[i]+1;
                  }
                  else{//没填过
                        c[i]=c[i-1]+1;
                  }
            }
      }
      /*
      for(int i=1;i<=n;i++) cout<<c[i]<<" ";
      cout<<endl;
      */
      if(is_ok) cout<<"YES"<<endl;
      else cout<<"NO"<<endl;
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--) solve();
      return 0;
}

一些特解不能留在那边,要按题意处理!

题目没有-1 -1的区间->要判0
image
image

Pushing Balls

https://codeforces.com/contest/2090/problem/B
注意要查向上向左一整条路径!!!
不要只查前一个点和起始点!!!

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int t;
int n,m;
bool check(int x,int y){
      
}
void solve(){
      cin>>n>>m;
      vector<string> a(n+1);
      for(int i=1;i<=n;i++){
            string s;
            cin>>s;
            s=' '+s;
            a[i]=s;
      }
      //只能从左侧和顶部推入
      //前面不能断
      bool is_ok=true;
      for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                        if(a[i][j]=='1'){
                              bool flag1=true,flag2=true;
                              for(int x=i;x>=1;x--){
                                    if(a[x][j]=='0'){
                                          flag1=false;
                                          break;
                                    }
                              }
                              for(int y=j;y>=1;y--){
                                    if(a[i][y]=='0'){
                                          flag2=false;
                                          break;
                                    }
                              }
                              if(flag1 || flag2) continue;
                              else{
                                    is_ok=false;
                                    break;
                              }
                        }
            }
            if(!is_ok) break;
      }
      if(is_ok) cout<<"YES"<<endl;
      else cout<<"NO"<<endl;
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--) solve();
      return 0;
}

智乃的“K”叉树

https://ac.nowcoder.com/acm/contest/103957/D
如何处理选择最小的一个?直接扫一遍 小于maxcnt就输出
注意考虑特判情况(n==2)

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=1e5+10;
//统计度数
int n;
//vector<int> g[N];
int d[N];
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>n;
      for(int i=1;i<n;i++){
            int u,v;
            cin>>u>>v;
            //g[u].push_back(v);
            //g[v].push_back(u);
            d[u]++;d[v]++;
      }
      //选择根节点 只有根节点会全取 其他都会-1
      //记得特判n==2
      if(n==2){
            cout<<"1 1"<<endl;
            return 0;
      }
      int maxcnt=-1;
      for(int i=1;i<=n;i++){
            maxcnt=max(maxcnt,d[i]);
      }
      cout<<maxcnt-1<<" ";
      for(int i=1;i<=n;i++){
            if(d[i]<maxcnt){
                  cout<<i;
                  return 0;
            }
      }
      return 0;
}

Serval and String Theory

https://codeforces.com/contest/2085/problem/A
关于字典序
只要该位被判断为小于/大于:那么就没有后面位数什么事了
只有等于才可以把希望保留到后位

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
const int INF=0x3f3f3f3f;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int t;
int n,k;
string s;
void solve(){
      cin>>n>>k;
      cin>>s;
      s=' '+s;
      //排序按顺序
      if(n==1) cout<<"NO"<<endl;
      else{
            //我只需要管第一个元素和最后一个元素即可 除非所有元素相同
            map<int,int> q;
            for(int i=1;i<=n;i++){
                  q[s[i]-'a']++;
            }
            if(q.size()==1){
                  cout<<"NO"<<endl;
                  return;
            }
            bool is_ok=false;
            //注意字典序:只要大就是大 小就是小!当该位已经被判断大/小后就没有后面位数什么事了
            for(int i=1;i<=n/2;i++){
                  if(s[i]<s[n-i+1]){
                        is_ok=true;
                        break;
                  }
                  //故判断完直接退出
                  else if(s[i]>s[n-i+1]){
                        is_ok=false;
                        break;
                  }
            }
            if(k==0){
                  if(is_ok) cout<<"YES"<<endl;
                  else cout<<"NO"<<endl;
            }
            else cout<<"YES"<<endl;
      }
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--) solve();
      return 0;
}

月饼

不要把简单的问题想复杂
https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7?problemSetProblemId=994805071789801472&page=1
直接从单价最高的开始选!!!贪心就能解决 不要去写多重背包哇
注意这里的表述:万吨/亿元->可以是小数->都要开double!!!

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
typedef long double ld;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=1010;
int n;
ld d;
struct node{
      ld s;
      ld cost;
}a[N];
bool cmp(node a,node b){
      return a.cost>b.cost;
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>n>>d;
      ld res=0;
      for(int i=1;i<=n;i++){
            cin>>a[i].s;
      }
      for(int i=1;i<=n;i++){
            ld tmp;
            cin>>tmp;
            a[i].cost=tmp/a[i].s;
      }
      ld ans=0;
      sort(a+1,a+1+n,cmp);
      //for(int i=1;i<=n;i++) cout<<a[i].cost<<" "<<a[i].s<<endl;
      for(int i=1;i<=n&&res<d;i++){
            if(a[i].s<=d-res){
                  res+=a[i].s;
                  ans+=a[i].cost*a[i].s;
            }
            else{
                  ld cnt=d-res;
                  res=d;
                  ans+=a[i].cost*cnt;
            }
      }
      cout<<fixed<<setprecision(2)<<ans;
      return 0;
}

Find the Car

https://codeforces.com/contest/1971/problem/E
注意处理不在端点上的值:直接推出原始数学公式 不要用double中间值!直接用整数形式写

//涉及到小数转整数的问题:直接用一行公式表示即可
ans+=(d-a[c])*t[c+1]/s[c+1];
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
int n,k,q;
//四舍五入 问路程求时间
void solve(){
    cin>>n>>k>>q;
    vector<int> a(k+1,0),b(k+1,0);//a路程 b时间
    vector<int> s(k+1,0),t(k+1,0);
    for(int i=1;i<=k;i++){
        cin>>a[i];
        s[i]=a[i]-a[i-1];
    }
    for(int i=1;i<=k;i++){
        cin>>b[i];
        t[i]=b[i]-b[i-1];
    }
    while(q--){
        ll d;
        cin>>d;
        //找到小于等于的最大
        int l=0,r=k;
        while(l<r){
            int mid=(l+r+1)/2;
            if(a[mid]<d) l=mid;
            else r=mid-1;
        }
        int c=l;
        ll ans=b[c];
        //涉及到小数转整数的问题:直接用一行公式表示即可
        ans+=(d-a[c])*t[c+1]/s[c+1];
        cout<<ans<<" ";
    }
    cout<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

红黑树

https://www.luogu.com.cn/problem/P12141
(1)对于搜索的复杂度判断要看清楚!别把O(2^n)看成O(n)
(2)一道看起来就不是搜索的问题:一定要想别的结论性的东西!
(3)完全二叉树和位运算关系很大

//结论:把行数列数转换为节点编号 统计二进制中1的个数 偶数为黑 奇数为红
void solve(){
    cin>>n>>k;
    int cnt=1<<(n-1);
    cnt+=(k-1);
    int res=0;
    for(int i=0;i<=30;i++){
        int t=(cnt>>i)&1;
        if(t==1) res++;
    }
    if(res%2) cout<<"RED"<<endl;
    else cout<<"BLACK"<<endl;
}

Apples in Boxes

https://codeforces.com/contest/2107/problem/B
注意最大值只有1个和有多个的情况!!!

void solve(){
    cin>>n>>k;
    vector<ll> a(n+1,0);
    map<ll,int> q;
    ll minn=INF,maxx=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        minn=min_(minn,a[i]);
        maxx=max_(maxx,a[i]);
        q[a[i]]++;
    }
    if(q[maxx]>1 && (maxx-minn)>k){
        cout<<"Jerry"<<endl;
        return;
    }
    if((maxx-minn-1)>k && q[maxx]==1){
        cout<<"Jerry"<<endl;
    }
    else{
        ll sum=0;
        for(int i=1;i<=n;i++){
            sum+=a[i];
        }
        if(sum%2){
            cout<<"Tom"<<endl;
        }
        else{
            cout<<"Jerry"<<endl;
        }
    }
}

Poi 的消消乐

https://ac.nowcoder.com/acm/contest/109080/D
造数据要全面!!!

int n;
string s;
/*
【注意打表要全面!】不要只考虑ABBB!!!
AAAAA:1
ABBAA:2 (AB可以互换)
AAABB:只能消A B最多保留3个
*/
void solve(){
    cin>>n;
    cin>>s;
    int ans=0;
    vector<int> pos1,pos2;
    pos1.push_back(0);
    for(int i=1;i<n;i++){
        if(s[i]!=s[0]){
            pos2.push_back(i);
        }
        else{
            pos1.push_back(i);
        }
    }
    if(pos2.size()==0){//AAAAA
        ans=1;
    }
    else if((pos1[pos1.size()-1]+1)==pos2[0]){
        if(pos2.size()>=4) ans=4;
        else ans=1+pos2.size();
    }
    else{
        ans=2;
    }
    cout<<ans<<endl;
}

Security 2

https://atcoder.jp/contests/abc407/tasks/abc407_c
本题需要思考:一点的按B次数应该如何确定?

//按B调整一个点 必须考虑当前点对【后续】节点的影响(前面的节点关系已经固定了所以随便调整)
/*
设b[i]是当前点要调整到目标值要按的次数
->(b[i]+b[i+1]+...+b[n])%10=s[i]
->【推公式】
(b[i]+b[i+1]+...+b[n])%10=s[i]
(b[i+1]+...+b[n])%10=s[i+1]
s[i]-s[i+1]=(10+b[i])%10
->(s[i]-s[i+1]+10)%10=b[i]
*/
string s;
void solve(){
    cin>>s;
    int n=s.size();
    int ans=n;
    for(int i=n-1;i>=0;i--){
        int u=s[i]-'0';
        int v=(i<n-1)?(s[i+1]-'0'):0;
        ans+=(10+u-v)%10;
    }
    cout<<ans;
}

Come a Little Closer

https://codeforces.com/contest/2114/problem/D

思路

关注到一个区间的x、y最大值和最小值同等重要
只能去掉一个点->考虑去掉每一个点
->如何维护去掉每一个点后的x、y最小值最大值?->multiset O(logn)

代码

int n;
void solve(){
    cin>>n;
    vector<ll> x(n+1,0),y(n+1,0);
    //框出来的地方至少留有1个格子:答案最少为n
    for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
    if(n==1){
        cout<<"1"<<endl;
        return;
    }
    multiset<ll> xpos,ypos;
    for(int i=1;i<=n;i++){
        xpos.insert(x[i]);
        ypos.insert(y[i]);
    }
    ll ans=INF;
    ll res1=*xpos.rbegin()-*xpos.begin()+1;
    ll res2=*ypos.rbegin()-*ypos.begin()+1;
    ans=res1*res2;
    for(int i=1;i<=n;i++){
        xpos.erase(xpos.find(x[i]));
        ypos.erase(ypos.find(y[i]));
        ll cnt1=*xpos.rbegin()-*xpos.begin()+1;
        ll cnt2=*ypos.rbegin()-*ypos.begin()+1;
        ll tmp=cnt1*cnt2;
        if(tmp==(n-1)){
            if(cnt1<cnt2) cnt2++;
            else cnt1++;
            tmp=cnt1*cnt2;
        }
        ans=min_(ans,tmp);
        xpos.insert(x[i]);
        ypos.insert(y[i]);
    }
    cout<<ans<<endl;
}

种类数

发现WA又觉得自己思路没问题->想想小细节 造数据看中间变量
https://ac.nowcoder.com/acm/contest/111309/E
注意数字被删到0后的数字种类的求法!->还需要看有没有初始0!!!

int n;
ll cal(ll n_,ll x_){
    return (n_%x_)?n_/x_+1:n_/x_;
}
int flag0=0;
void solve(){
    cin>>n;
    set<ll> q;
    vector<ll> a(n+1,0);
    for(int i=1;i<=n;i++){
        ll tmp;
        cin>>tmp;
        q.insert(tmp);
    }
    int cnt=0;
    for(auto son:q){
        a[cnt++]=son;
    }
    //for(int i=0;i<cnt;i++) cout<<a[i]<<" ";
    ll x=cnt;
    ll ans=0;
    ll pl=0;
    int cnt2=0;
    for(int i=0;i<cnt;i++){
        if(a[i]==a[0]) cnt2++;
        if(a[0]==0) flag0=1;
    }
    if(cnt2==cnt){
        cout<<0<<endl;
        return;
    }
    for(int i=0;i<cnt;i++){
        //找相同性质的
        int j=i;
        while(cal(a[j],x)==cal(a[i],x) && j<cnt) j++;
        j--;
        for(int k=i;k<=j;k++) a[k]-=pl;
        int len=j-i+1;
        ans+=cal(a[i],x);
        pl+=cal(a[i],x)*x;
        if(flag0){
            if(a[i]!=0){
                x-=len;
            }
        }
        else{
            x-=(len-1);
            flag0=1;
        }
        i=j;
    }
    cout<<ans<<endl;
}

Gellyfish and Baby's Breath

https://codeforces.com/contest/2116/problem/B
观察最大数的性质

思路

注意到2的次方:差1能差一倍
那么区间最大只可能从p最大 q最大 p对应最大 q对应最大产生
->提前维护最大值

代码

const ll mod=998244353;
int n;
ll qmi(ll a,ll k,ll p){
	ll res=1;
	while(k){
		if(k&1) res=res*a%p;
		k>>=1;//删去k的末位 
		a=a*a%p;
	}
	return res;
}
void solve(){
    cin>>n;
    vector<ll> p(n+1,0),q(n+1,0);
    vector<int> pmax(n+1,0),qmax(n+1,0);
    for(int i=1;i<=n;i++) cin>>p[i];
    for(int i=1;i<=n;i++) cin>>q[i];
    ll maxx=p[1];
    pmax[0]=1;
    for(int i=1;i<=n;i++){
        pmax[i]=pmax[i-1];
        if(p[i]>maxx){
            maxx=p[i];
            pmax[i]=i;
        }
    }
    maxx=q[1];
    qmax[0]=1;
    for(int i=1;i<=n;i++){
        qmax[i]=qmax[i-1];
        if(q[i]>maxx){
            maxx=q[i];
            qmax[i]=i;
        }
    }
    //for(int i=1;i<=n;i++) cout<<pmax[i]<<" "<<qmax[i]<<endl;
    vector<ll> ans(n+1,0);
    for(int i=1;i<=n;i++){
        int x=pmax[i],y=qmax[i];
        int a=i-pmax[i]+1,b=i-qmax[i]+1;
        if(p[x]>q[y]) ans[i]=(qmi(2LL,p[x],mod)+qmi(2LL,q[a],mod))%mod;
        else if(q[y]>p[x]) ans[i]=(qmi(2LL,q[y],mod)+qmi(2LL,p[b],mod))%mod;
        else if(q[a]>p[b]) ans[i]=(qmi(2LL,p[x],mod)+qmi(2LL,q[a],mod))%mod;
        else ans[i]=(qmi(2LL,q[y],mod)+qmi(2LL,p[b],mod))%mod;
    }
    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
    cout<<endl;
}

小红的数组查询(二)

https://ac.nowcoder.com/acm/contest/111159/C
注意看题意!会有和想的不同的情况->认真造数据->会发现需要特判

int d,p;
int q;
int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
void solve(){
    cin>>d>>p;
    cin>>q;
    int cnt=p/gcd(d,p);
    while(q--){
        int l,r;
        cin>>l>>r;
        int len=r-l+1;
        /*【题目有诈骗!】
        a[1]一定==1
        若p==1 -> mod完一定是0 -> 要特判
        */
        if(p==1){
            if(l==1 &&r>1) cout<<2<<endl;
            else cout<<1<<endl;
            continue;
        }
        if(len<cnt) cout<<len<<endl;
        else cout<<cnt<<endl;
    }
}

cats 学乘法

https://acm.hdu.edu.cn/contest/problem?cid=1177&pid=1001

错因

分类讨论有问题:对于0 只需要判断其个数是不是==0 和奇偶没关系

题目大意

一个数组 所有数乘积是一个正整数
每次可以选择一个数+1或者-1,求最小操作次数

思路

如果负数是奇数->出来的乘积是负数
对于0?一定要操作,可以是机动的
如果没有0:要么操作最大的负数变成1,要么操作最小的正数变成-1
如果有0:可以*分出奇数个0构造成-1*,其他0构造成1

代码

const int N=3e5+10;
int n;
void solve(){
    cin>>n;
    vector<i64> a(n+1,0);
    i64 zhen=0,zero=0,fu=0;
    i64 ans=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(a[i]>0) zhen++;
        else if(a[i]==0){
            zero++;
            ans++;
        }
        else fu++;
    }
    //cout<<zhen<<" "<<zero<<" "<<fu<<endl;
    //正整数
    i64 maxn=-inf_i64;
    for(int i=1;i<=n;i++){
        if(a[i]<0) maxn=max64(a[i],maxn);
    }
    i64 minn=inf_i64;
    for(int i=1;i<=n;i++){
        if(a[i]>0) minn=min64(a[i],minn);
    }
    if((fu%2)){
        if(zero==0){
            ans+=min64((1LL-maxn),(minn+1LL));
        }
    }
    cout<<ans<<endl;
}

Arboris Contractio

https://codeforces.com/contest/2131/problem/D

题目大意

ebf323f4-a305-452f-953f-c891998c63c1

思路

只有叶节点会对答案有贡献
对于一个点 连出去的叶节点已经满足条件不用管->删去

如何统计叶节点?

dfs暴力扫图?
可以直接统计叶节点!度数为1即可

不要想到一些错误结论:eg我只需要管度数最多的点即可
有些度数不多的点也可以构造出更优的答案:只要直接连的叶节点够多

代码

const int N=3e5+10;
int n;
vector<int> g[N];
//统计每个节点连出去的节点的叶节点:本身不算,直接统计就行
//*看度数*即可,不用dfs
void init(int x){
    for(int i=1;i<=x;i++) g[i].clear();
}
void solve(){
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    int sum=0;
    for(int i=1;i<=n;i++){
        if(g[i].size()==1) sum++;
    }
    int ans=inf_int;
    for(int i=1;i<=n;i++){
        int res=0;
        for(auto son:g[i]){
            if(g[son].size()==1) res++;
        }
        ans=min(ans,sum-res);
    }
    if(n==2) ans=0;
    cout<<ans<<endl;
    init(n);
}

Alternated

https://atcoder.jp/contests/abc421/tasks/abc421_c

题目大意

给定一个长度为\(2n\)的字符串,有n个A,n个B
要求相邻两个字符不能相同,一次操作规定为交换相邻字符,问最少需要多少次操作

思路

只能构造为ABABAB...BABABA...
->那只需要看A是不是在对应位置上就行(看一个字母即可
->判断方式:肯定是趋近放

代码

int n;
string s;
void solve(){
    cin>>n;
    cin>>s;
    s=' '+s;
    vector<int> pos;
    for(int i=1;i<=2*n;i++){
        if(s[i]=='A'){
            pos.push_back(i);
        }
    }
    int cnt=1;
    i64 ans1=0;
    for(auto son:pos){
        ans1+=(i64)(abs(son-cnt));
        cnt+=2;
    }
    cnt=2;
    i64 ans2=0;
    for(auto son:pos){
        ans2+=(i64)(abs(son-cnt));
        cnt+=2;
    }
    i64 ans=min64(ans1,ans2);
    cout<<ans<<endl;
}

小红的整数三角形

https://ac.nowcoder.com/acm/contest/116945/C

题目大意

image

思路

注意三角形面积为整数:长宽至少有一个是偶数!!!
不要直接上来就构造

代码

i64 a1,b1,a2,b2;
void solve(){
    cin>>a1>>b1>>a2>>b2;
    if(a1==a2){
        i64 x3=a1+2LL,y3=b1;
        cout<<x3<<" "<<y3<<endl;
        return;
    }
    if(b1==b2){
        i64 x3=a1,y3=b1+2LL;
        cout<<x3<<" "<<y3<<endl;
        return;
    }
    if(llabs(a1-a2)%2LL && llabs(b1-b2)%2LL){
        if((a1+1LL)==a2) cout<<(a1-1LL)<<" "<<b2<<endl;
        else cout<<(a1+1LL)<<" "<<b2<<endl;
    }
    else{
        cout<<a1<<" "<<b2<<endl;
    }
}

Incremental Path

https://codeforces.com/contest/2151/problem/B

注意把\(n^2\)暴力的东西转成扫一遍的问题

题目大意

一个无限长的数组 一些点被涂成了黑块
两种操作:
A:往后挪一格
B:往后挪到最近的白色格子
给出操作序列,共操作n次,每次操作序列为[1~n],
每次操作结束后停下来的那个点变成黑色
求最终黑色块序列

思路

手玩一下这个过程
发现涂黑色块,下次重新走过的这个过程相当于:
先把当前白色块涂成黑色块,然后再找下一个白色点走

代码

int n,m;
string s;
void solve(){
    cin>>n>>m;
    cin>>s;
    set<int> a;
    for(int i=1;i<=m;i++){
        int x;
        cin>>x;
        a.insert(x);
    }
    int cur=1;
    for(auto c:s){
        cur++;
        if(c=='B'){
            while(a.count(cur)) cur++;
        }
        a.insert(cur);
        /*更新下一个命令的起始位置:
        如果下一个位置是A:那么会先往后跳一格再标记黑
        ->符合一个一个跳的逻辑:因为下一次跳A之前还会跳B,无论如何会略过一个格子
        如果下一个位置是B:下次直接跳*/
        if(c=='B'){
            while(a.count(cur)) cur++;
        }
    }
    cout<<a.size()<<endl;
    for(auto son:a) cout<<son<<" ";
    cout<<endl;
}
posted @ 2025-02-10 00:21  White_ink  阅读(28)  评论(0)    收藏  举报