A:
void solve()
{
int a, b, c; cin>>a>>b>>c;
if(a==b) cout<<c;
else if(b==c) cout<<a;
else cout<<b;
cout<<'\n';
}
B:
string s[4];
map<char, int> mp;
void solve()
{
mp.clear();
for(int i=1; i<=3; ++i)
cin>>s[i];
for(int i=1; i<=3; ++i)
for(int j=0; j<3; ++j)
if(s[i][j]!='?') mp[s[i][j]]++;
for(auto x:mp)
if(x.second==2) {cout<<x.first<<'\n'; return ;}
}
C:
int n, x;
void solve()
{
cin>>n;
ll sum = 0;
for(int i=1; i<=n; ++i) cin>>x, sum += x;
if(sum/(ll)sqrt(sum)==sqrt(sum)) cout<<"YES"<<'\n';
else cout<<"NO"<<'\n';
}
D:
关键在于判断字符串尾部的越界问题,可能会导致 ' . ' 的添加位置出现错误,也会影响最后对s输出长度。
思路:
判断' . '的位置从元音的出现位置i入手,如果s[i+2]是辅音,证明这是一个"辅元辅"的单词,否则是一个"辅元"的单词。
特判:
在字符串结尾添加一个辅音,如果现在s以"辅元辅辅"结尾,此时会在倒数第二个位置添加一个'.'如果以"辅元辅"结尾,s[i+2]为空,所以也会在倒数第二个位置添加一个'.'。
最后只需要输出s.size()-2的字符串就好了。
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0); cin.tie(0), cout.tie(0)
int n;
string s;
void solve()
{
cin>>n>>s;
s += 'b';//为尾部插入一个辅音,保证无论以什么形式结尾,倒数第二个字符都将会是'.'
for(int i=0; i<s.size(); ++i)//此处一定要用s.size()或s.length(),字符串的长度在随时更新
if(s[i]=='a' or s[i]=='e') {
if(s[i+2]=='b' or s[i+2]=='d' or s[i+2]=='c')
s.insert(i+2, 1, '.');
else//此处等效于s[i+2]为元音 or 为空(越界)
s.insert(i+1, 1, '.');
++i;
}
cout<<s.substr(0, s.size()-2)<<'\n';
}
signed main(void)
{
ios;
int t=1; cin>>t;
while(t--) solve();
return 0;
}
E:
算法:前缀和
看数据范围可知,暴力O(n^2)会t,必须实现O(nlog(n))以内的查询方法,因为是连续区间问题,由此可想到前缀和,树状数组,线段树等。本题选择简单的前缀和。
思路:
先模拟题意,构造一个前缀和数组,奇 + 偶 - (反过来也可以)
如果此时a[i]==0,可知区间[1, i]是满足题意的,结束solve。
否则用map记录a[i]的值,当map[a[i]]出现第二次时,代表区间 [1, r1] 与区间 [1, r2] 的前缀和是相等的,因此区间 [r1, r2] 的值为两区间相减==0, 满足题意,结束solve()。
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0); cin.tie(0), cout.tie(0)
typedef long long ll;
const int MAXN=200010;
ll n, a[MAXN];
map<ll, int> mp;
void solve()
{
cin>>n;
mp.clear();
for(int i=1; i<=n; ++i) cin>>a[i];
for(int i=1; i<=n; ++i)
{
if(i%2==1) a[i] = a[i-1]+a[i];
else a[i] = a[i-1]-a[i];
if(a[i]==0) {cout<<"YES"<<endl; return ;}
mp[a[i]]++;
if(mp[a[i]]>=2) {cout<<"YES"<<endl; return ;}
}
cout<<"NO"<<endl;
}
signed main(void)
{
ios;
int t=1; cin>>t;
while(t--) solve();
return 0;
}
F:
算法:离散化,树状数组
一维线段之间的相遇关系,对于线段(x1, x4), (x2, x3) 只有 x1<x2 并且 x4>x3 时才会相遇。
思路:
因为数据范围过大,因此首先考虑离散化,用一条线段树(bushi扫描线从一边到另一边。
接下来设计查询算法,必须控制在O(log(n))以内,所以容易想到二分,树状数组,线段树。又因为二分时需要保证有序,能查询到所在位置,还要增删元素,复杂度系数过大导致容易超时,真不是因为我wa了才回头的,线段树较费时,所以选择树状数组。
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0); cin.tie(0), cout.tie(0)
#define lowbit(x) (x&(-x))
typedef long long ll;
const int MAXN=200010;
struct Line {//离散化,标记关键节点
int x, tag, num;//x用来排序, tag入边为1,出边为-1, num表示是第几条线段。
bool operator<(const Line &t) const{return x<t.x;}//重载小于号, 可以用cmp替代
}c[MAXN<<1];
int n, a[MAXN], b[MAXN], d[MAXN];
inline void update(int x, int f) {//树状数组区间更新,f只可能为1或-1
for(int i=x; i<=MAXN; i+=lowbit(i))
d[i] += f;
}
inline ll query(int x) {//统计区间[1, x]存在的元素个数
ll ans = 0;
for(int i=x; i; i-=lowbit(i))
ans += d[i];
return ans;
}
void solve()
{
cin>>n;
for(int i=1; i<=n; ++i)
{
cin>>a[i]>>b[i];
c[i]={a[i], 1, i};
c[i+n]={b[i], -1, i};
}
n<<=1;//n变为2n
sort(c+1, c+n+1);//升序排序,没有重载小于号可以写个cmp放sort里
ll ans = 0, cur = 0;//cur表示入边的先后
memset(d, 0, sizeof d);
for(int i=1; i<=n; ++i)
{
if(c[i].tag==1) update(++cur, 1), a[c[i].num] = cur;//标记num是第cur条进去的边
else {
ans += query(a[c[i].num]);//统计cur小于等于它的个数(包含了自己)
update(a[c[i].num], -1);//出边,将他的贡献从中减去
}
}
//因为统计query时包括了自己,所以最后ans减去点的个数,n之前扩大了一倍,所以为n/2
cout<<ans-n/2<<'\n';
}
signed main(void)
{
ios;
int t=1; cin>>t;
while(t--) solve();
return 0;
}
G:
算法:Dijkstra,最短路, 动态规划
题意明显为最短路问题,但有个自行车权值,floyd会超时,蒟蒻不会johnson全源最短路,因此选择二维的dijkstra算法
思路:
将原算法的 dis 与 vis 改为二维,其余基本一致
dis[i][j]表示 从原点,中途用过的最小系数为j的自行车,到i点的最小时间。
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0); cin.tie(0), cout.tie(0)
#define endl '\n'
//#define int long long 懒人专用
typedef long long ll;
const ll inf = 0x7fffffff;
const int MAXN=1010, MAXM=1010;
//链式前向星
struct Edge {
ll to, dis, next;//此处dis为边的权值
}e[MAXM<<1];//正反建边开两倍空间
struct St {
ll dis;//此处dis为权值
ll pos;//此处pos为fr
ll rate;//自行车系数
bool operator<(const St &t) const{return dis>t.dis;}
};
int n, m, cnt;
bool vis[MAXN][MAXN];
//dis[i][j]表示从原点,中途用过的最小系数为j的自行车,到i点的最小时间
ll dis[MAXN][MAXN], head[MAXN], b[MAXN];
priority_queue<St> q;
inline void add_edge(int u, int v, int w)
{
e[++cnt].dis = w;
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
}
inline void dijkstra()//堆优化迪杰斯特拉
{
dis[1][b[1]] = 0;
q.push((St){0, 1, b[1]});
while(!q.empty())
{
ll fr = q.top().pos, bike = q.top().rate;
q.pop();
if(vis[fr][bike]) continue;
vis[fr][bike] = true;
for(int i=head[fr]; i; i=e[i].next)
{
ll to = e[i].to, minbike = min(bike, b[to]);
if(dis[to][minbike] > dis[fr][bike] + e[i].dis*bike)
{
dis[to][minbike] = dis[fr][bike] + e[i].dis*bike;
if(!vis[to][minbike]) {
q.push((St){dis[to][minbike], to, minbike});
}
}
}
}
}
void solve()
{
cin>>n>>m;
memset(e, 0, sizeof e);
memset(head, 0, sizeof head);
for(int i=1; i<=1000; ++i)
for(int j=1; j<=1000; ++j)
dis[i][j] = inf*inf, vis[i][j] = 0;
cnt = 0;
for(int i=1; i<=m; ++i)
{
ll u, v, w; cin>>u>>v>>w;
add_edge(u, v, w);
add_edge(v, u, w);//无向图反向建边
}
for(int i=1; i<=n; ++i) cin>>b[i];
dijkstra();
ll ans = inf*inf;//inf为int上限,inf*inf接近longlong上限
for(int i=1; i<=n; ++i)
ans = min(ans, dis[n][b[i]]);
cout<<ans<<endl;
}
signed main(void)
{
ios;
int t=1; cin>>t;
while(t--) solve();
return 0;
}
蒟蒻不易qvq,佬佬们点个赞再走吧Orz,感谢观看。