省赛第一次训练赛题解
创始人
2024-05-30 16:14:54
0

省赛第一次训练赛题解

A(CF1451C)

由于没有操作次数的限制,很容易想到对于任意 k 个相同的字符,他们都可以通过交换换到一起之后修改。而对于两个按照字母顺序排序之后相同的字符串,从第一个也可以经过若干交换换到第二个。

所以问题变成了:在两个字符序列中,一次可将 k 个相同的字母变为它的下一个,问是否能把第一个变成第二个。

注意数据,不能直接a,b进行排序。但是可以统计字母出现次数,然后从字母 a 开始到字母 z,每次把第一个串中当前字母的个数,通过变成下一个字母,变得和第二个串的个数一样,如果不可行就输出 No。这样就线性通过此题。

#include
using namespace std;
int a[100010];
void slove(){string s1,s2;int n,k;cin>>n>>k;cin>>s1>>s2;int a[30]={0},b[30]={0};for(auto ch:s1){a[ch-'a']++;}for(auto ch:s2){b[ch-'a']++;}for(int i=0;i<26;i++)if(a[i]>=b[i]){if((a[i]-b[i])%k!=0) {cout << "No" << '\n';return ;}elsea[i+1]+=a[i]-b[i];}else {cout << "No" << '\n';return ;}cout<<"Yes"<<'\n';
}int main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t;cin>>t;while(t--){slove();}return 0;
}

B(CF1793C)

这题本来是个蛮简单的题,但是审题没审清楚,没注意这是一个排列,一直在处理重复元素,hash,单调栈,map什么的都尝试过

很典的一个双指针,用两个变量,一个记录最大值一个记录最小值,然后双指针从左右两侧向中间靠,再讨论四种情况,不断更新左右最大值最小值

#include
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int a[N];
int n;
int main()
{cin.tie(0);cout.tie(0);ios::sync_with_stdio(false);int t;cin >> t;while (t--){cin >> n;		for (int i = 1; i <= n; i++){cin >> a[i];			}int ma = n;int mi = 1;int l = 1, r = n;int ansl = 0, ansr = 0;while (r - l + 1 >= 4){bool flag = 0;//判断当前区间是否满足四种情况中的一种while (a[r] == ma && r - l + 1 >= 4){//右端点是最大值r--;//右端点左移ma--;//最大值-1flag = 1;}if (r - l + 1 < 4)break;while (a[r] == mi && r - l + 1 >= 4){//右端点是最小值r--;//右端点左移mi++;//最小值+1flag = 1;}if (r - l + 1 < 4)break;while (a[l] == ma && r - l + 1 >= 4){//左端点是最大值l++;//左端点右移ma--;//最大值-1flag = 1;}if (r - l + 1 < 4)break;while (a[l] == mi && r - l + 1 >= 4){//左端点是最小值mi++;//最小值+1l++;//左端点右移flag = 1;}if (!flag){//四种情况都没有发生ansl = l, ansr = r;break;}}if (!ansl){cout << -1 << endl;}else{cout << ansl << " " << ansr << endl;}}return 0;
}

C(CF1738B)

  • 先从s的后k项判断一下a的后面k-1项是不是满足递增的

  • 然后数学推导一下会发现a的前n-k+1项,最大值就两种情况,s(n-k+1)/(n-k+1)或者s(n-k+1)/(n-k+1)+1,这里的/都是向下取整

    #include
    using namespace std;
    typedef long long ll;
    ll s[200010];
    void slove(){int n,k;cin>>n>>k;ll pre=0;for(int i=1;i<=k;i++) {cin >> s[i];}pre=s[2]-s[1];for(int i=3;i<=k;i++){if(s[i]-s[i-1]cout<<"No"<<'\n';return;}elsepre=s[i]-s[i-1];}if(k==1) {cout << "Yes" << '\n';}else if(s[1]>=0){if(s[1]%(n-k+1)){if(s[1]/(n-k+1)+1<=s[2]-s[1])cout<<"Yes"<<'\n';elsecout<<"No"<<'\n';}else{if(s[1]/(n-k+1)<=s[2]-s[1])cout<<"Yes"<<'\n';elsecout<<"No"<<'\n';}}else{if(s[1]/(n-k+1)<=s[2]-s[1])cout<<"Yes"<<'\n';elsecout<<"No"<<'\n';}
    }
    int main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t;cin>>t;while(t--){slove();}return 0;
    }
    

D(CF1753A1)

又审题审错了,看成了每个si都要为0,实际上是si的和为0,1200的题都没做出。。。。。

  • 如果数组长度为奇数,那不可能构造出
  • 数组长度为偶数,可以发现,ai和a(i+1)若相同,则将他们组成一个区间,若不同,则将他们分为两个长度为1的区间,这样他们的s相加也为0
#include 
using namespace std;
#define pii pair
const int maxn = 200010;int n, a[maxn];
void solve() {cin>>n;for (int i = 1; i <= n; ++i) {cin>>a[i];}if (n & 1)  {cout<<-1<<'\n';return;}vector ans;for (int i = 1; i <= n; i += 2) {if (a[i] == a[i+1]) {ans.push_back({i, i + 1});} else {ans.push_back({i, i});ans.push_back({i + 1, i + 1});}}cout<cout<ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t;cin>>t;int cas = 1;while (t--) {solve();}return 0;
}

E(CF1753A2)

这题是上个题的困难版本,改动的条件是a数组不止由1和-1组成,还有可能有0

和上一个题其实相差也不多,可以考虑这么构造,相邻两个相等依旧选择把他们放到一个区间,不相等就判断是不是有0,如果没有0,那就分为两个区间,有0,再往后面看一位,若这个数和原来的那个非0数相等则将三个数放入一个区间,否则三个数构成三个区间。总而言之,这里面的0是可以忽略的,那么我们把0忽略后,就变成了上面那个简单版问题

同时还看到一个更巧妙的解法:

考虑分段的本质是什么,其实就是给每个元素乘上 11 或 −1−1,不能有两个相邻的元素都乘上 −1−1。

于是考虑,初始时假设每个元素都乘上了 11,现在我们需要将其中一些元素改为乘上 −1−1,修改的两个元素不能相邻。

直接贪心地选取即可,从前往后枚举每个元素,判断若当前元素乘上 −1−1,元素和的绝对值是否会减小,若减小就操作,然后记录一下,下一个元素不能再乘上 −1−1。

贪心的正确性也很好证明,若当前元素乘上 −1−1 后,元素和的绝对值会减小,但是我们不修改当前元素,那么下一个元素最多也只会让元素和的绝对值减小相同的数,所以我们先对当前元素进行修改,一定不会更劣,就做完了。

#include 
using namespace std;
int wz[200005],n,a[200005],b[200005],x[200005],L[200005],R[200005];
int main(){int t;cin >> t;while(t--){int n;cin >> n;int cnt=0,ok=0,len=0;for (register int i=1;i<=n;i++){cin >> a[i];if (a[i]!=0) b[++cnt]=a[i],wz[cnt]=i;//记录每个非0位置的信息}if (cnt%2==1){cout << -1 << endl;//无解continue ;}for (register int i=1;i<=cnt;i+=2){if (b[i]!=b[i+1]){//第二种情况for (register int j=wz[i-1]+1;j<=wz[i+1];j++){L[++len]=R[len]=j;//每段单独分}}else {if (wz[i]+1==wz[i+1]) L[++len]=wz[i-1]+1,R[len]=wz[i+1];//相邻就直接分,注意要从上个非0位置+1开始else {for (register int j=wz[i-1]+1;j<=wz[i];j++) L[++len]=R[len]=j;//i之前全部单独分for (register int j=wz[i]+1;j<=wz[i+1]-2;j++) L[++len]=R[len]=j;L[++len]=wz[i+1]-1,R[len]=wz[i+1];//给第i+1个非零位置前留下一个0使它在区间里的长度变为偶数}}}if (R[len]L[len+1]=R[len]+1,R[len+1]=n;len++;//可能最后一个非零数后面还有,单独再开一段}cout << len << '\n';for (register int i=1;i<=len;i++) cout << L[i] << ' ' << R[i] << endl;}
}
#include
# define sum(x,y) (s[y]-s[x-1])
using namespace std;
inline int rd(){int f=1,s=0;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c<='9'&&c>='0'){s=(s<<3)+(s<<1)+(c^48);c=getchar();}return s*f;
}
const int N = 2e5;
int t,n,s[N+5],f[N+5],g[N+5],a[N+5];
int main(){t=rd();while(t--){n=rd();int sum=0,cnt=n;for(int i=1;i<=n;++i)a[i]=rd(),sum+=a[i],g[i]=0;for(int i=2;i<=n;++i)if(abs(sum-2*a[i])printf("%d\n",cnt);g[n+1]=0;for(int i=1;i<=n;++i){if(g[i])continue;if(g[i+1])printf("%d %d\n",i,i+1);else printf("%d %d\n",i,i); }	}}return 0;
}

F(CF1761C)

一个图论的构造题,先建图把优先级确定,让真子集指向父集合,初始可以把集合1到n初始值都赋为自己的下标i,如集合3初始值3,这样就能避免重复了,接着这就是一个标准的拓扑排序的题了,只不过在拓扑排序的过程中我们要进行集合加法,这个用set可以很容易解决

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 110;
int  ind[maxn];
void slove() {int n, x;cin >> n;vectorg[maxn];vector>ans(maxn);for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++) {scanf("%1d", &x);if (x)ind[j]++, g[i].push_back(j);}for(int i=1;i<=n;i++)ans[i].insert(i);queueq;for (int i = 1; i <= n; i++)if (ind[i]==0)q.push(i);while (q.size()) {int u = q.front();q.pop();for (int i = 0; i < g[u].size(); i++) {if ((--ind[g[u][i]]) == 0) {q.push(g[u][i]);}for(auto it:ans[u])ans[g[u][i]].insert(it);}}for (int i = 1; i <= n; i++) {cout<ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t;cin >> t;while (t--) {slove();}return 0;
}

G(CF1788C)

构造方法:根据等差数列求和公式可以判断构造是否存在,以及第一项的值a,接着第一项选取1和a-1,然后选取3,a-1,也就是第一项加2,第二项-1,这样就可以等差数列的条件了,当第一个数大于等于第二个数时停止上诉操作,然后选取第一项为2,重复第一项+2,第二项-1的操作,可以数学证明,能够取完所有的数

#include
using namespace std;
const int N = 1e3 + 5;
typedef long long ll;
int main()
{cin.tie(0);cout.tie(0);ios::sync_with_stdio(false);int t;cin >> t;while (t--){ll n;cin >> n;if (n & 1){cout << "YES" << endl;ll b = 2 * n - n / 2;//s/n-n/2-1ll a = 1;for (int i = 1; i <= (n + 1) / 2; i++){//遍历n范围内的所有奇数,构成第1个到中间的数对cout << a << " " << b << endl;a += 2;b--;}a = 2, b = 2 * n;//2和s/n+1-2for (int i = 1; i <= n / 2; i++){//遍历n范围内所有偶数cout << a << " " << b << endl;a += 2;b--;}}else{cout << "NO" << endl;}}return 0;
}

H(CF1741D)

因为只能交换子树,所以可以从叶子节点往上走,每次都更新子树中的数的左右边界,如果两个子树的区间出现了交叉,那么必然不可以通过交换满足题目要求,反之就判断谁在前谁在后,也就是是否需要交换

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
struct {int l=INT_MAX,r=0;
}tree[maxn*2];
int m,ans=0,flag=0;
void dfs(int u){if(u>=m||flag)return;dfs(u*2);dfs(u*2+1);if(tree[u*2].l<=tree[u*2+1].r&&tree[u*2].r>=tree[u*2+1].l||tree[u*2+1].l<=tree[u*2].r&&tree[u*2+1].r>=tree[u*2].l)flag=1;else if(tree[u*2].l>=tree[u*2+1].r)ans++;
}
void slove(){cin >> m;for(int i=m;i<2*m;i++)cin>>tree[i].l,tree[i].r=tree[i].l;for(int i=m;i<2*m;i+=2){int a=i/2;while(a){tree[a].l=min(tree[a*2].l,tree[a*2+1].l),tree[a].r=max(tree[a*2].r,tree[a*2+1].r);a/=2;}}dfs(1);if(flag)cout<<-1<<'\n';elsecout<ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t;cin >> t;while (t--) {slove();flag=0;ans=0;}return 0;
}

相关内容

热门资讯

紧急提醒:卸载!卸载!有人账户... 转自:恩施发布一条警方紧急提醒日前冲上热搜“中银会议”“银联会议”“抖音会议”这些App都是诈骗软件...
中信证券:当下迎来平衡港A配比...   来源:中信证券研究  文|裘翔 高玉森 杨家骥 刘春彤  6月以来市场最大的变化是逐步从存...
东西问|杜建录:西夏陵为何正式... 中新社银川7月13日电 题:西夏陵为何正式列入《世界遗产名录》?——专访宁夏大学人文与民族学部部长、...
超七成民众支持加沙全面停火 以... #超七成以民众支持加沙全面停火##以再爆发大规模示威要求加沙停火#【超七成民众支持加沙全面停火 以色...
容城县举办毛绒玩具行业技能竞赛 转自:河工新闻网  河工新闻网讯(记者彭海峰 通讯员刘玉)7月10日,由容城县总工会主办、容城县毛绒...
警方紧急提醒:卸载!卸载!有人... 来源:厦门日报 一条警方紧急提醒日前冲上热搜“中银会议”“银联会议”“抖音会议”这些App都是诈骗软...
筹划控制权变更,扬电科技7月1... 转自:北京商报北京商报讯(记者 马换换 王蔓蕾)7月13日晚间,扬电科技(301012)披露公告称,...
在《人民日报》发文的农民伯伯,... 转自:北京日报客户端读书,把自己弄得好一点我叫刘诗利,家住河南濮阳,农忙时在家种地,不忙的时候,进城...
高三女生吃聪明药上瘾:“提分神... 转自:北京时间 【#高三女生吃聪明药上瘾#:“提分神药”...
华药集团工会举办电钳自动化创新... 转自:河工新闻网  河工新闻网讯(记者张青 通讯员李胜娟 于文静)近日,华北制药集团有限责任公司(以...