目录
瞎编乱造第一题
瞎编乱造第二题
瞎编乱造第三题
瞎编乱造第四题
瞎编乱造第五题
不是很想编了但还是得编的第六题
不是很想编了但还是得编的第七题
还差三道题就编完了的第八题
还差两道题就编完了的第九题
太好啦终于编完了
因为偶数因子的操作是可逆,所以我们只要匹配奇数因子就可以了
输入的时候我们就把每个偶数元素一直除到奇数
之后我们枚举b数组每一位右移
匹配上就标记一下
如果全匹配上就是Yes,否则就是No
#include
using namespace std;const int MAXN = 200005;
int a, bb, b[MAXN];
bool vis[MAXN];void solve()
{int n;cin >> n;for (int i = 1; i <= n; ++i){vis[i] = 0;}multiset sa;for (int i = 1; i <= n; ++i){cin >> a;while ((a & 1) == 0){a >>= 1;}sa.insert(a);}for (int i = 1; i <= n; ++i){cin >> bb;while ((bb & 1) == 0){bb >>= 1;}b[i] = bb;}for (int j = 0; j < 32; ++j){for (int i = 1; i <= n; ++i){if (vis[i]){continue;}auto it = sa.find(b[i] >> j);if (it != sa.end()){sa.erase(it);vis[i] = 1;}}}cout << (sa.empty() ? "YES\n" : "NO\n");return;
}
signed main(){int tt;cin>>tt;while(tt--){solve();}
}
对区间总体加减可以转化为差分问题
第一个操作可以转化为第一个数差分-1,选一个位置差分+1
第二个操作可以转化为选一个位置差分-1
第三个操作可以转化为第一个数差分加1
我们把所有的差分求出来后,先将从2-n所有差分归零,在将第一个数归零即可
代码如下
#include
using namespace std;
#define int long long
const int N=1e6+10;
int n, m, k;
int a[N], d[N];
signed main() {ios::sync_with_stdio(false), cin.tie(0);int T;cin >> T;while (T -- ) {cin >> n;for (int i = 1; i <= n; i ++) cin >> a[i];for (int i = 1; i <= n; i ++) d[i] = a[i] - a[i - 1];int res = 0;for (int i = 2; i <= n; i ++)if (d[i] < 0) {res -= d[i];d[1] += d[i]; }else res += d[i];res += abs(d[1]);cout << res << '\n';}return 0;
}
只要从2-n的每个a[i]都是a[1]的倍数即可满足条件
反之则不行
#include
using namespace std;
#define int long long
const int N=1e6+10;
signed main() {ios::sync_with_stdio(false), cin.tie(0);int T;int t=1;cin>>t;while(t--) {int n;cin>>n;int a1;cin>>a1;int flag=1;for (int i=2; i<=n; i++) {int x;cin>>x;if (x%a1!=0)flag=0;}if(flag==1) cout<<"Yes";else cout<<"No"; cout << endl;}return 0;
}
当n为奇数时候,先手必胜,因为只要先手第一轮全拿走,第二轮后手就会拿到你的位置,他就输了
当n为偶数时,因为每个人拿的堆是固定的,所以只要看一下谁最少的堆个数少,谁就会先拿完
谁就输了
要是都相等,就是先手输
代码如下
#include using i64 = long long;void solve() {int n;std::cin >> n;std::vector a(n);std::array step{};for (int i = 0; i < n; i++) {std::cin >> a[i];}if (n % 2 == 1) {std::cout << "Mike\n";return;}for (int t = 0; t < 2; t++) {int min = std::numeric_limits::max();int j = -1;for (int i = t; i < n; i += 2) {if (a[i] < min) {min = a[i];j = i / 2;}}step[t] = 1LL * (n / 2) * min + j;}if (n % 2 == 1 || step[0] > step[1]) {std::cout << "Mike\n";} else {std::cout << "Joe\n";}
}int main() {// freopen("9.in","r",stdin);// freopen("9.out","w",stdout);std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int t;std::cin >> t;while (t--) {solve();}return 0;
}
只要这个字符串的最后两位不相等,这个字符串就一定满足条件
所以只要遍历一遍,找两个不相等的字符,贡献就是遍历到他的索引(这个代码里有解释)
之后再加上n(每个单独的字符串都满足条件)
#include
using namespace std;
#define int long long
const int N=1e6+10;
signed main() {// ios::sync_with_stdio(false), cin.tie(0);int T;cin>>T;while(T--) {long long sum = 0;int n;scanf("%lld", &n);string s = " ";cin >> s;for(int i = 1; i < n; i++){if(s[i] != s[i - 1]){//+ i的原因在于//以i这个位置的字符结尾的子串恰好是这么多//↑比如说"1001"的"01",以他们结尾的子串是"1001" "001" "01"正好对应索引3 //如果末位2字符成立,所有子串都成立,反之亦然//而这里是没有把"1"和"0"算进去的,他们必然是成立的,所以直接在外面加就行了 sum += i;}}printf("%lld\n", (sum + n));}return 0;
}
只要找到x的最低位一并保留即可
如果x只有唯一一位1,答案就要再加1(最低位保留一个1,保证异或大于0)
特判一下1
#include
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
#define INF 0x3f3f3f3f
#define lowbit(x) ((x)&(-x))
const ll MOD = 1000000007;
// const ll MOD = 998244353;
const int N = 500010;void slove()
{int n;cin >> n;if(n == 1){cout << 3 << '\n';return;}ll ans = lowbit(n);if(ans != n)cout << ans << '\n';elsecout << ans+1 << '\n';
}int main(void)
{// freopen("9.in","r",stdin);// freopen("9.out","w",stdout);IOS;int tt = 1;cin >> tt;while(tt--){slove();}return 0;
}
我们找到一个最先变成奇数的数(如果本来就有奇数,那就不需要这步)
把他变成奇数
之后所有的偶数加上这个奇数变成奇数
代码如下
#include
using namespace std;
#define int long long
const int N=1e6+10;
#define lowbit(x) ((x)&(-x))
int a[N];
signed main() {// ios::sync_with_stdio(false), cin.tie(0);int T;cin>>T;while(T--) {int n;cin >> n;for(int i=1;i<=n;++i){cin >> a[i];}int ans = 0;for(int i=1;i<=n;++i){if(a[i]&1)ans++;}if(ans){cout << n-ans << '\n';continue;}int minn = 1e9+7;for(int i=1;i<=n;++i){int tmp = lowbit(a[i]);int cnt = 0;while(tmp != 1){tmp/=2;cnt++;}minn = min(minn , cnt);}cout << minn+n-1 << '\n';}return 0;
}
就把所有数像山一样排起来就好了,中间大两边小
>2数量的x对答案的贡献是1
(假如这样一个数组,1 1 2 2 3 3 4 4,这样排好之后答案就是4,每个数都有两个以上,每个数都贡献1,排好之后1 2 3 4 4 3 2 1)
其他=1的x对答案贡献是总的这样的数/2上取整
(假如这样一个数组,1 2 3 4 5,排好之后答案是3,因为贡献是5/2上取整,排好之后1 3 5 4 2)
这两组贡献加起来
#include using i64 = long long;void solve() {int n;std::cin >> n;std::map cnt;for (int i = 0; i < n; i++) {int x;std::cin >> x;if (cnt[x] < 2) {cnt[x]++;}}int ans = 0, v = 0;for (auto [x, c] : cnt) {if (c == 2) {ans++;} else {v++;}}ans += (v + 1) / 2;std::cout << ans << "\n";
}int main() {// freopen("10.in","r",stdin);// freopen("10.out","w",stdout);std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int t;std::cin >> t;while (t--) {solve();}return 0;
}
每个陷阱最初的贡献是a[i]-(n-i),先按这个排好序
(躲掉的伤害减去之后增加的伤害)
接下来考虑陷阱之间相互作用
前面每跳过一个陷阱,后面陷阱躲掉的伤害就+1,贡献也+1
所以是排好序的数组遍历前k个
满足a[i]-(n-i)+(前面跳过的陷阱数)>0这个等式,就可以跳
#include
using namespace std;
#define int long long
const int N=1e6+10;
#define lowbit(x) ((x)&(-x))
int a[N];
signed main() {// ios::sync_with_stdio(false), cin.tie(0);int T;cin>>T;while(T--) {long long sum = 0;int n, k;cin >> n >> k;for (int i = 1; i <= n; ++i){cin >> a[i];sum += a[i];a[i] -= n - i;}sort(a + 1, a + 1 + n, greater());for (int i = 1; i <= k; ++i){if (a[i] > -i){sum -= a[i] + i - 1;}else{break;}}cout << sum << '\n';}return 0;
}
对于每个前面是>后面是<的位置,把它称之为山谷
也包括第一个<左边的位置和最后一个>右边的位置
我们让每个山谷都是0
之后向两边扩散,每层加1
每个取max就好
代码如下
#include
using namespace std;
string a;
int arr[500002]= {0,};
int main()
{cin>>a;int n = a.size();for(int i=0;i=0;i--){if(a[i]== '>')arr[i] = max(arr[i+1]+1,arr[i]);}long long sum = 0;for(int i=0;i<=n;i++){sum += arr[i];}cout<