A
给你一个整数 n n n 和三个字符串 a , b , c a, b, c a,b,c,每个字符串由 n n n 个小写字母组成。
假设一个模板是由 n n n 个字母组成的字符串 t t t。如果从 1 1 1 到 n n n 的所有 i i i 都满足以下条件,则字符串 s s s 与模板 t t t 匹配:
- 如果模板中第 i i i 个字母是小写字母,那么 s i s_i si 必须与 t i t_i ti 相同;
- 如果模板中的第
i
i
i 个字母是小写字母,那么
s
i
s_i
si 必须与
t
i
t_i
ti 的小写版本不同。例如,如果模板中有字母
A
,则不能在字符串的相应位置使用字母a
。
因此,如果至少有一个 i i i 的条件不成立,字符串就与模板不匹配。
判断是否存在模板 t t t,使得字符串 a a a 和 b b b 匹配,而字符串 c c c 不匹配。
只要至少有一个位置使得 c i ≠ a i 且 c i ≠ b i c_i \ne a_i 且 c_i \ne b_i ci=ai且ci=bi即可
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define trav(a,x) for(auto&a : x)
#define all(x) x.begin(),x.end()
#define sz(x) (int) x.size()
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef long long ll;
string a,b,c;
int n;
void work()
{
cin>>n;
cin>>a>>b>>c;
int tot=0;
rep(i,0,n-1)
{
if(a[i]==b[i])
{
if(c[i]==a[i]) tot++;
}
else
{
if(a[i]==c[i]) tot++;
if(b[i]==c[i]) tot++;
}
}
if(tot==n) cout<<"NO\n";
else cout<<"YES\n";
}
int main()
{
cin.tie(0);
cin.sync_with_stdio(0);
int t=1;
cin>>t;
while(t--)
work();
return 0;
}
B
给定 n n n个长度为 2 a i 2^{a_i} 2ai的小木棍,问组成三角形有多少种方法
显然只有等边和等腰两种情况,分开计数即可
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define trav(a,x) for(auto&a : x)
#define all(x) x.begin(),x.end()
#define sz(x) (int) x.size()
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef long long ll;
map<int,int> mp;
ll cal2(int n)
{
return (ll)n*(n-1)/2;
}
ll cal3(int n)
{
return (ll)n*(n-1)*(n-2)/6;
}
void work()
{
int n;
cin>>n;
rep(i,1,n)
{
int x;cin>>x;
mp[x]++;
}
int sum=0;
ll ans=0;
trav(item,mp)
{
ans+=cal3(item.second);
ans+=cal2(item.second)*sum;
sum+=item.second;
}
cout<<ans<<'\n';
mp.clear();
}
int main()
{
cin.tie(0);
cin.sync_with_stdio(0);
int t=1;
cin>>t;
while(t--)
work();
return 0;
}
C
给定数轴上 n n n个城市的坐标,去最近的城市只要花费 1 1 1枚硬币,去其他城市需要花费路程长度枚硬币,数据保证每个城市的最近城市唯一
m m m次询问 x x x到 y y y城市的最小花费
容易发现能走花费为 1 1 1的边就一定走,花费不能为 1 1 1就只能花费,于是问题转化成前缀和
n < = 1 e 5 n<=1e5 n<=1e5
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define trav(a,x) for(auto&a : x)
#define all(x) x.begin(),x.end()
#define sz(x) (int) x.size()
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef long long ll;
const int maxn=1e5+5;
int n;
int l[maxn],r[maxn],a[maxn];
ll suml[maxn],sumr[maxn];
void work()
{
cin>>n;
sumr[0]=suml[0]=0;
rep(i,1,n)
cin>>a[i];
rep(i,1,n)
{
if(i==1) {r[i]=1;continue;}
if(i==n) {l[i]=1;continue;}
if(a[i]-a[i-1]>a[i+1]-a[i])
r[i]=1,l[i]=a[i]-a[i-1];
else
l[i]=1,r[i]=a[i+1]-a[i];
}
rep(i,1,n)
sumr[i]=sumr[i-1]+r[i],suml[i]=suml[i-1]+l[i];
int q;
cin>>q;
while(q--)
{
int x,y;
cin>>x>>y;
if(x<y)
cout<<sumr[y-1]-sumr[x-1]<<'\n';
else
cout<<suml[x]-suml[y]<<'\n';
}
}
int main()
{
cin.tie(0);
cin.sync_with_stdio(0);
int t=1;
cin>>t;
while(t--)
work();
return 0;
}
D
n n n只怪兽,给定每只怪兽的攻击力和防御力 a i , d i a_i,d_i ai,di
n n n轮,每轮每只怪兽会受到相邻两只怪兽的攻击,如果攻击力之和大于其防御力则死亡
输出这 n n n轮中每一轮死亡的怪兽数量
n < = 3 e 5 n<=3e5 n<=3e5
需要证明一下复杂度
如果怪兽在上一轮没有死亡,那么,只有当它上一轮相邻的两只中有一只死亡,我们才需要进行判断
每只怪兽至多被删除一次,故时间复杂度 O ( n ) O(n) O(n)
用链表维护即可
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define trav(a,x) for(auto&a : x)
#define all(x) x.begin(),x.end()
#define sz(x) (int) x.size()
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef long long ll;
const int maxn=3e5+5;
int pre[maxn],nxt[maxn],a[maxn],d[maxn];
bool vis[maxn],del[maxn];
int n;
queue<int> s,s1;
void work()
{
cin>>n;
rep(i,1,n) cin>>a[i];
rep(i,1,n) cin>>d[i];
a[n+1]=d[n+1]=0;
rep(i,1,n) pre[i]=i-1,nxt[i]=i+1,s.push(i);
nxt[0]=1;
rep(i,1,n)
{
int res=0;
while(!s.empty())
{
int pos=s.front();s.pop();
if(vis[pos]) continue;
if(a[pre[pos]]+a[nxt[pos]]>d[pos]) res++,s1.push(pos),del[pos]=true;
vis[pos]=true;
}
while(!s1.empty())
{
int pos=s1.front();s1.pop();
//printf("pos=%d\n",pos);
if(pre[pos]&&!del[pre[pos]]) s.push(pre[pos]),vis[pre[pos]]=false;
if(nxt[pos]!=n+1&&!del[nxt[pos]]) s.push(nxt[pos]),vis[nxt[pos]]=false;
pre[nxt[pos]]=pre[pos];
nxt[pre[pos]]=nxt[pos];
}
cout<<res<<' ';
}
cout<<'\n';
rep(i,1,n) vis[i]=false,del[i]=false;
//while(!s1.empty()) s1.pop();
//while(!s.empty()) s.pop();
}
int main()
{
cin.tie(0);
cin.sync_with_stdio(0);
int t=1;
cin>>t;
while(t--)
work();
return 0;
}
E
给定一个 X X X,构造一个长度不超过 200 200 200的恰好有 X X X个最长上升子序列的序列(其中空序列算一个)
X < = 1 e 18 X<=1e18 X<=1e18
首先需要发现一个长度为 n n n的单调递增的序列恰好有 2 n − 1 2^n-1 2n−1个最长上升子序列
用 2 n − 1 2^n-1 2n−1去凑 X X X会超过200的限制
想到向中间插入几个较大值,假设插入的位置为 x x x,就刚好有 2 x 2^x 2x的贡献,那么本题就解决了
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define trav(a,x) for(auto&a : x)
#define all(x) x.begin(),x.end()
#define sz(x) (int) x.size()
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef long long ll;
const int inf =1e8+5;
void work()
{
ll x;
cin>>x;
ll tmp=x;
int n=0;
while(tmp)
{
tmp>>=1ll;n++;
}
int ans=n-1;
rep(i,0,n-2)
if(x>>i&1) ans++;
cout<<ans<<'\n';
rep(i,0,n-1)
{
if(i) cout<<i<<' ';
if(x>>i&1&&i!=n-1) cout<<inf<<' ';
}
cout<<'\n';
}
int main()
{
cin.tie(0);
cin.sync_with_stdio(0);
int t=1;
cin>>t;
while(t--)
work();
return 0;
}
F
给定长度为 n n n的序列 a n a_n an,值域为 [ 1 , x ] [1,x] [1,x],
每次可以选定一段区间 [ l , r ] [l,r] [l,r],和这段区间内不包含的一个数 k ( k ≤ x ) k(k \le x) k(k≤x),将区间中所有的数全都变成 k k k
问最少几次操作可以使得序列 a a a全部相等
x , n ≤ 500 x,n \le 500 x,n≤500
区间DP
设 f [ l ] [ r ] [ k ] f[l][r][k] f[l][r][k]为将区间 [ l , r ] [l,r] [l,r]变为 k k k的最小代价, g [ l ] [ r ] [ k ] g[l][r][k] g[l][r][k]表示将区间 [ l , r ] [l,r] [l,r]变为不包含 k k k的最小代价
那么有 f [ l ] [ r ] [ k ] = m i n ( f [ l ] [ i ] [ k ] + f [ i + 1 ] [ r ] [ k ] , g [ l ] [ r ] [ k ] + 1 ) f[l][r][k]=min(f[l][i][k]+f[i+1][r][k],g[l][r][k]+1) f[l][r][k]=min(f[l][i][k]+f[i+1][r][k],g[l][r][k]+1)
g [ l ] [ r ] [ k ] = m i n ( g [ l ] [ i ] [ k ] + g [ i + 1 ] [ r ] [ k ] ) , 且 g [ l ] [ r ] [ k ] = m i n ( g [ l ] [ r ] [ i ] + 1 ) ( i ≠ k ) g[l][r][k]=min(g[l][i][k]+g[i+1][r][k]),且g[l][r][k]=min(g[l][r][i]+1)(i \ne k) g[l][r][k]=min(g[l][i][k]+g[i+1][r][k]),且g[l][r][k]=min(g[l][r][i]+1)(i=k)
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define trav(a,x) for(auto&a : x)
#define all(x) x.begin(),x.end()
#define sz(x) (int) x.size()
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef long long ll;
const int inf=1e8;
const int maxn=105;
int f[maxn][maxn][maxn],g[maxn][maxn][maxn],a[maxn];
int n,x;
void work()
{
cin>>n>>x;
rep(i,1,n)
rep(j,1,n)
rep(k,1,x)
f[i][j][k]=g[i][j][k]=inf;
rep(i,1,n)
{
cin>>a[i];
rep(j,1,x)
f[i][i][j]=(a[i]!=j),
g[i][i][j]=(a[i]==j);
}
rep(len,1,n)
rep(l,1,n-len+1)
{
int r=l+len-1,minn=inf;
rep(k,1,x)
{
rep(i,l,r-1)
g[l][r][k]=min(g[l][i][k]+g[i+1][r][k],g[l][r][k]);
minn=min(minn,g[l][r][k]);
}
rep(k,1,x)
g[l][r][k]=min(g[l][r][k],minn+1);
rep(k,1,x)
rep(i,l,r-1)
f[l][r][k]=min(f[l][i][k]+f[i+1][r][k],min(g[l][r][k]+1,f[l][r][k]));
}
int ans=inf;
rep(i,1,x)
ans=min(ans,f[1][n][i]);
cout<<ans<<'\n';
}
int main()
{
cin.tie(0);
cin.sync_with_stdio(0);
int t=1;
cin>>t;
while(t--)
work();
return 0;
}