地址:
签到题,思路就是找到两个不递增的位置,交换两个位置的值,然后再遍历一边看看满不满足整体递增。
#include
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
int a[1005] = { 0 };
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int i, vi = -1;
for (i = 1; i < n; i++) {
if (a[i] > a[i + 1]) {
vi = i;
break;
}
}
if (vi == -1) {
cout << "Sorted" << '\n';
return 0;
}
int minh = INT_MAX, v2 = ++i;
for (i; i <= n; i++) {
if (minh > a[i]) {
minh = a[i];
v2 = i;
}
}
swap(a[vi], a[v2]);
for (i = 1; i < n; i++) {
if (a[i] > a[i + 1]) {
cout << "Failed" << '\n';
return 0;
}
}
cout << "Sorted" << '\n';
return 0;
}
数学题。计算每个点的次数期望可以从之前的位置的点推迟来。
公式: E [ n ] = 1 + 1 n ∑ i = 0 n − 1 E [ i ] E[n] = 1 + \frac{1} {n} \sum_{i=0}^ {n-1} E[i] E[n]=1+n1i=0∑n−1E[i]
#include
using namespace std;
const int M = 1e5 + 10;
// const int mod =
double E[M],preE[M];
inline void solve() {
int N = 1e5 + 1;
E[0]=0,E[1]=1.0;
// if (N == 1) {
// printf("%.15lf\n",E[1]);
// return;
// }
for (int n=2;n<=N;n++) {
preE[n-1]=E[n-1];
preE[n-1] += preE[n-2];
E[n]=1 + 1.0 / n * preE[n-1];
}
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
solve();
while (T--) {
int n;
cin >> n;
printf("%.15lf\n",E[n]);
}
return 0;
}
挺好想的,首先如果第一的数是偶数,那么那么门与门之间就会死循环,不会跳到下一个,之后如果有第一个数是奇数那么之后到第n-1个房间一定是偶数,这样才能配合一个第一个留下来的门去变成奇数个门。
结论:第一个是奇数,且2到n-1是偶数才为yes,否则是false;
#include
using namespace std;
int a[100005];
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
if (n == 1) {
cout << "Yes\n";
} else if (n == 2) {
if (a[0] % 2 == 0) {
cout << "No\n";
} else {
cout << "Yes\n";
}
} else {
bool odd = false;
for (int i = 1; i < n-1; i++) {
if (a[i] % 2 == 1) {
odd = true;
break;
}
}
if (odd) {
cout << "No\n";
} else {
if (a[0] % 2 == 0 ) {
cout << "No\n";
} else {
cout << "Yes\n";
}
}
}
}
return 0;
}
模拟,没什么好说的。
#include
const double pai = 3.141592654;
using namespace std;
const int MAXN = 100005;
int a[MAXN];
signed main() {
ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int T=1;
cin>>T;
while(T--) {
string a;
cin>>a;
a='&'+a;
if (a[2]=='-') {
int tep = abs(a[3]-a[1]);
double ans = 50.0*sin(tep * 1.0 / 8.0 * pai);
printf("%.10lf\n",2 * ans);
}else if (a[2]=='>') {
int tep=0;
if (a[1]<a[3]) {
tep = a[3]-a[1];
}else {
tep = a[3] + 8 - a[1];
}
double ans = 2 * pai * 50 * (tep * 1.0 / 8);
printf("%.10lf\n",ans);
}else if (a[2]=='<') {
int tep=0;
if (a[1]<a[3]) {
tep = 8 + a[1] - a[3];
}else {
tep = a[1] - a[3];
}
double ans = 2 * pai * 50 * (tep * 1.0 / 8);
printf("%.10lf\n",ans);
}else if (a[2]=='v') {
double ans = 2 * 50.0;
printf("%.10lf\n",ans);
}
}
return 0;
}
滑动窗口+单调队列
这道题的根本在于知道一个窗口怎么判断是不是好数组呢,我们可以从这个窗口中找到最小前缀和的值,然后和这个窗口的前一个值(这里者的是前面所有值的前缀和)比较,如果最小的值都大于前面的值,那么把前面的值去掉之后窗口中仍然前缀和是正的即合法。
为了避免循环取余问题,我们用2倍原数组来模拟循环移位。
以示例举例
Q[0] = 0
Q[1] = 2 // 0+2
Q[2] = 5 // 0+2+3
Q[3] = 1 // 0+2+3-4
Q[4] = 2 // 0+2+3-4+1
Q[5] = 1 // 0+2+3-4+1-1
Q[6] = 3 // 0+2+3-4+1-1+2
Q[7] = 6 // 0+...+2+3
Q[8] = 2 // 0+...+2+3-4
Q[9] = 3 // 0+...+2+3-4+1
Q[10]= 2 // 0+...+2+3-4+1-1
滑动窗口最小值计算
窗口大小 n=5,计算每个窗口的最小值:
窗口 [1,5](下标1~5):min(2,5,1,2,1)=1
窗口 [2,6](下标2~6):min(5,1,2,1,3)=1
窗口 [3,7](下标3~7):min(1,2,1,3,6)=1
窗口 [4,8](下标4~8):min(2,1,3,6,2)=1
窗口 [5,9](下标5~9):min(1,3,6,2,3)=1
存储结果:minInWindow = [?, 1, 1, 1, 1, 1](下标1~5)
检查移位条件
遍历每个移位 k(0~4),检查 Q[k] <= minInWindow[k+1]:
k=0:Q[0]=0 <= minInWindow[1]=1 → 满足
移位后数组:[2,3,-4,1,-1]
前缀和:[2,5,1,2,1](全部≥0)
k=1:Q[1]=2 > minInWindow[2]=1 → 不满足
移位后数组:[3,-4,1,-1,2]
前缀和:[3,-1,…](-1<0,无效)
k=2:Q[2]=5 > minInWindow[3]=1 → 不满足
移位后数组:[-4,1,-1,2,3]
前缀和:[-4,…](-4<0,无效)
k=3:Q[3]=1 <= minInWindow[4]=1 → 满足
移位后数组:[1,-1,2,3,-4]
前缀和:[1,0,2,5,1](全部≥0)
k=4:Q[4]=2 > minInWindow[5]=1 → 不满足
移位后数组:[-1,2,3,-4,1]
前缀和:[-1,…](-1<0,无效)
具体解释看代码!
#include
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<int> a(n);
long long total = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
total += a[i];
}//先判读一下所有数字的和,如果所有数字和都小于0,那么就没有合法的数组了。
if (total < 0) {
cout << 0 << endl;
return 0;
}
vector<int> A(2 * n);//数组扩充,避免循环取余问题,简化操作
for (int i = 0; i < n; i++) {
A[i] = a[i];
A[i + n] = a[i];
}
vector<long long> Q(2 * n + 1, 0);//前缀和数组用来存放每个坐标的前缀和
for (int i = 1; i <= 2 * n; i++) {
Q[i] = Q[i - 1] + A[i - 1];
}
vector<long long> minInWindow(n + 1, 0);//记录窗口中的最小值
deque<int> dq;//双端队列实现单调递增,注意dq中存放的是坐标
for (int j = 0; j < 2 * n; j++) {
while (!dq.empty() && Q[dq.back()] >= Q[j]) {
dq.pop_back();
}
dq.push_back(j);
if (dq.front() <= j - n) {//要保证求的最小前缀和在窗口内
dq.pop_front();
}
if (j >= n) {
int i = j - n + 1;
if (i >= 1 && i <= n) {
minInWindow[i] = Q[dq.front()];//窗口的长度到达数组长度后就将最小值赋给miInWindown容器
}
}
}
int count = 0;
//将每一个值都和后面窗口的最小值比较,窗口最小值大于等于当前值才合法
//因为证明窗口减去前面一大堆后仍然有能力保证前缀和大于等于0
for (int k = 0; k < n; k++) {
if (Q[k] <= minInWindow[k + 1]) {
count++;
}
}
cout << count << endl;
return 0;
}