====== CF 655 div2 ====== ===== A ===== 水题,吓唬人的。 #include #include #include using namespace std; int main() { int t; cin >> t; while(t--) { int n; cin >> n; for (int i = 1; i <= n;i++) cout << 1 << ' '; cout << endl; } return 0; } ===== B ===== 给出一个 n,要求两个正整数 a 和 b,使得 a+b=n 并且 LCM(a, b) 尽量小。多组数据。 **思路**:找出 n 的大于 1 的最小因子 k,a = n/k,b = n - n/k。不会证明,感觉是对的。 #include #include #include #include using namespace std; int main() { int t; cin >> t; while(t--) { int n; cin >> n; int flag = 1; for (int i = 2; i <= sqrt(n);i++) { if((n/i)*i == n) { cout << n - (n / i)<<' '< ===== C ===== 对于一个序列,定义一个操作,选定连续的区间,将里面的数字重排,保证没有数字在原本的位置。现在给你一个 n 的排列 a,问你最少操作多少次,可以让 a 变成严格单增数列。 **题解**:显然,情况1:如果a本来就单调增,则为0次。情况2:如果没有一个数字在对应位置上,则为1次。情况3:在其他情况下,总能找到一个方法,对全部的区间重排,使得每个数字都不在自己原本的位置上并且不是最终要求的位置,这样就能转化为情况2,所以答案为2。 #include #include #include #include using namespace std; const int MAX = 2e5 + 20; int pic[MAX]; int main() { int t; cin >> t; while(t--) { int n; cin >> n; int flag = 0,pos = -1; for (int i = 1; i <= n;i++) { scanf("%d", &pic[i]); if(pic[i]!=i && flag == 0) flag = 1,pos = i; } if(flag == 0) { cout << 0 << endl; } else { int posend = 0; for (int i = n; i >= 1;i--) if(pic[i]!=i) { posend = i; break; } for (int i = pos; i <= posend;i++) { if(pic[i] == i) { flag = 114514; break; } } if(flag == 114514) { cout<<2< ===== D ===== 给定一个长度为奇数的环形区间,每次可以选择一个数,把这个数字替换成和这个数字相邻的两个数字的和,并删去相邻的两个数字,直到只剩下一个数字。求这个数字的最大值 **题解**:一开始想区间dp,发现数据太大搞不了,又想优先队列贪心,后面又发现不太对。实际上,如果我进行了一次操作,得到了一个新数字a,那么我的下一次操作就最好不要选择与a相邻的数,因为这样的话,实际上相当于在原来的环上删掉了2个数字(因为a是原本环上两个数字 的和),按照这个思路贪心即可。实现的话,直接拆环就行。 #include #include using namespace std; typedef long long ll; const int maxn = 4e5+55; ll a[maxn]; ll c[maxn]; ll d[maxn]; int main(){ int n; ll sum=0; scanf("%d",&n); for(int i=0;i=2)c[i]=c[i-2]+a[i]; else c[i]=a[i]; } for(int i=n-1;i>=0;--i){ if(i<=n-3)d[i]=d[i+2]+a[i]; else d[i]=a[i]; } ll maxx=c[0]; for(int i=0;i