A - Hard Way
题意:给出三角形三个顶点的坐标(均为整数),称无法连一条直线到x轴而不通过三角形内部的边是unsafe的,求这个三角形unsafe的边长之和。
解:显然和y轴平行且另一个顶点在其下方的边是unsafe的。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,m,k,q; int x[3],y[3]; signed main() { int T; scanf("%d",&T); while(T--){ for(int i=0;i<3;i++) scanf("%d%d",&x[i],&y[i]); int ans=0; if(y[0]==y[1]&&y[1]>y[2]) ans= abs(x[0]-x[1]); else if(y[1]==y[2]&&y[2]>y[0]) ans= abs(x[1]-x[2]); else if(y[0]==y[2]&&y[2]>y[1]) ans= abs(x[0]-x[2]); printf("%d\n",ans); } return 0; }
B - Power Walking
题意:给出n个数,将其任意分为k组,令f(x)为第x组不同的数的个数,分别求k=1,2,3,...,n时,f(1)+...+f(k)的值。
解:最后答案和重复的数相关。假设这串数为111222333,k=1时,只有一种分法,答案为3;k=2时,将1独立出去,答案还是3;k=3时,123各自独立,答案为3;k=4时,有一个集合不得不有两个数了,答案为4;k=n时,答案为n。综上,假设集合中有x种不同的数,当k<=x时,答案为x;当k>x时,答案为k。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,m,k,q; signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d",&n); set<int> s; int t; for(int i=1;i<=n;i++){ scanf("%d",&t); s.insert(t); } for(int i=1;i<=s.size();i++) printf("%d ",s.size()); for(int i=s.size()+1;i<=n;i++) printf("%d ",i); printf("\n"); } return 0; } // 111222333444555666 // 1 6 2 6 3 6 4 6 5 6 6 6 7 7 8 8 //111 222 333 444 5556 66
C - Great Sequence
题意:给出n个数和x,可以以任意方式排列。求最小添加多少个数,可以使得对于每一个a2i,都有a2i*x=a2i+1.
解:有a2i*x的时候,取这个数;没有就添一个。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,x; signed main() { int T; scanf("%d",&T); while(T--){ map<ll,int> m; scanf("%d%d",&n,&x); int t; for(int i=1;i<=n;i++){ scanf("%d",&t); m[t]++; } ll ans=0; for(auto [now,num]:m){ for(int i=0;i<num;i++){ if(m[now*x]) m[now*x]--; else ans++; } } printf("%lld\n",ans); } return 0; }
D. Repetitions Decoding
题意:给出一串数,每次可以在任意位置添加任意相同的两个字母。求一种方法(操作数不一定要最少),使得这串数能分成若干段,其中每一段都能分成两个相同的子数组。
解:构造题。首先每个数字要出现偶数次,不然怎么加都是奇数,不可能平分。先观察样例,比如123321,可以通过在中间添加两个2,再加两个1。获得方法:当这串数对称时,可以在中间连续加;当它不对称时,如122313,可以按上述方法在1后面加两个2,为了写起来简单,不判断是否原来有连续两个2,再加两个,最后在中间加两个3,这样有一对对称了。按这个方法连续处理,可以证明能处理完,并且对称的情况也适用。However,这玩意到底该怎么写。。。。
先膜一下大佬的写法。由于每次增加两个数,但其实我们只用它的一半,另一半刚好是它的反转。所以写的时候不用插入,而是删除和反转。然后就很好写了。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,x; signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d",&n); vector<int> a; map<int,int> m; int t; for(int i=0;i<n;i++){ scanf("%d",&t); a.push_back(t); m[t]++; } int flag=0; for(auto [x,y]:m){ if(y%2){ printf("-1\n"); flag=1; break; } } if(flag) continue; vector<pair<int,int> > ans1; vector<int> ans2; int cnt=0; for(int i=1;i<=n/2;i++){ auto it=++a.begin(); //不能是a.begin()++ while(*it!=*a.begin()) it++; int t=it-a.begin(); for(int j=1;j<=t-1;j++) ans1.push_back(make_pair(cnt+j+t,a[j])); reverse(a.begin()+1,a.begin()+t); a.erase(it); //先删it,不然迭代器会错位 a.erase(a.begin()); cnt+=t*2; ans2.push_back(t*2); } printf("%d\n",ans1.size()); for(auto [x,y]:ans1) printf("%d %d\n",x,y); printf("%d\n",ans2.size()); for(auto i:ans2) printf("%d ",i); printf("\n"); } return 0; } // abba -> abaaba // abcddcba -> abcdabcddcbadcba // ac -> acaa -> acac ca // abc -> -1 // abdabd dbcdbc cbbcbb bb -> abdabd dbcdbc // addcbcaddcbc cbcddb -> addcbca dd b // addcbcab -> addcbcaddcbc cbcddb // 1313 32232222 //3211232112 211211 11