【简单题】敲响警钟!!!
【简单题】
真的是醉了
对于一道题 要分清什么是重要的 什么是不重要的 只关注重要的 没有思路就不要想复杂
一定不要把结论想当然!一定要注意讨论所有情况!!!
举手赢棋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
错因
只考虑到同层情况 没考虑到隔一层也有可以满足的情况

代码
#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


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
题目大意

思路
只有叶节点会对答案有贡献
对于一个点 连出去的叶节点已经满足条件不用管->删去
如何统计叶节点?
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
题目大意

思路
注意三角形面积为整数:长宽至少有一个是偶数!!!
不要直接上来就构造
代码
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;
}

浙公网安备 33010602011771号