题意:懂得都懂
思路:直接记录有几个不高兴的,给他们互相换换即可
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
int fa[100005];
int n,m;
void solve(){
int ans=0;
int n;
cin>>n;
vector<int >g(n+1);
for (int i = 1; i <=n ; ++i) {
cin>>g[i];
}
int p=0;
for (int i = 1; i <=n ; ++i) {
if(g[i]==i){
p++;
}
}
ans+=max((p+1)/2,(int)0);
cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
}
题意:问1-n中,最长的n的因子的连续区间的长度为多少
思路:结论表明最长的区间必然是从1开始的区间,假设我们找到的1到5这个区间都是因子,如果存在一个区间的长度是大于这个区间的话,比如9-14,那么我们可以发现其中的长度是等于6的,那么证明其中一定存在6的因子,那么其实就可以发现我们前面那个区间的长度又可以扩大了,1-6,依次类推,那么我们就可以从1枚举,找到第一个不是因子的数i,i-1为答案
diamond:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
const int mod=1e9+7;
int fa[100005];
int n,m;
//int find(int x){
// if(fa[x]!=x){
// fa[x]=find(fa[x]);
// }
// return fa[x];
//}
//void merge(int x,int y){
// int dx=find(x),dy=find(y);
// fa[dy]=dx;
//}
void solve() {
unordered_map<ll, ll> has;
int x;
cin >> x;
int ans=0;
int p=0;
for (int i = 1; i <=500 ; ++i) {
if(x%i==0){
p++;
}
else{
ans=max(ans,p);
p=0;
}
}
ans=max(p,ans);
cout<<ans<<'\n';
// for (int i = 2; i <= x / i; ++i) {
// while (x % i == 0) {
// has[i]++;
// x /= i;
// }
// }
// if (x > 1)
// has[x]++;
// ll cnt = 1;
// for (auto p: has) {
// cnt = cnt * (p.second + 1) % mod;
// cout<<p.first<<' '<<p.second<<endl;
// }
// set<int>st;
// for (auto i:has) {
//
// }
// cout << cnt;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
}
/* 2 2
* ld
* ul
* 1 1
* 1 1
*
*/
题意:给一个数组,每次操作我们可以把一个数加到另一个数上,可以加本身,问我们怎么操作才能使数组是递增的
思路:直接按照Hard版本的讲,我们可以看到题目给的次数是$k<=31$次,如果我们数组全部为正或为负,那么我们最多19次求一遍前缀和或者后缀和即可,那么如果存在不同的,我们其他的12次就可以用来变负为正或者变正为负的操作,假设我们得到$abs(max)>=abs(min)$,正的绝对值>=负的绝对值,我们首先考虑变负为正,我们最多变12次,那么当负的个数<=12,我们就可以直接操作,假设>12,那么考虑把正的变为负,因为正的只有<=7个,我们先把$abs(min)$变为大于等于$abs(max)$,最差情况,min=-1,我们对他进行加自己的操作,那么-1 -2 -4 -8 -16 -32,最差进行5次操作即可>=正的最大值,最后把正的变为负,再进行后缀和操作,刚好是5+7+19=31次操作,如果$abs(max)<abs(min)$,反过来操作即可
diamond:
#include<bits/stdc++.h>
using namespace std;
//#define int long long
//#define ll long long
const int mod=1e9+7;
int fa[100005];
int n,m;
#define endl '\n'
void solve() {
cin>>n;
vector<int >g(n+1);
vector<pair<int,int>>ans;
int ma=-99,mi=99;
int idxma=0,idxmi;
int zheng=0,fu=0;
for (int i = 1; i <=n ; ++i) {
cin>>g[i];
if(g[i]>=0)zheng++;
else
fu++;
if(ma<g[i]) {
ma = max(ma, g[i]);
idxma=i;
}
if(mi>g[i]) {
mi = min(mi, g[i]);
idxmi=i;
}
}
if(mi>=0){
cout<<n-1<<endl;
for (int i = 1; i <=n-1 ; ++i) {
cout<<i+1<<' '<<i<<endl;
}
return;
}
if(ma<=0){
cout<<n-1<<endl;
for (int i = n; i >1 ; --i) {
cout<<i-1<<' '<<i<<endl;
}
cout<<endl;
return;
}
if(abs(ma)>=abs(mi)){
if(fu<=12){
for (int i = 1; i <=n ; ++i) {
if(g[i]<0){
// cout<<i<<' '<<idxma<<endl;
ans.push_back({i,idxma});
}
}
for (int i = 1; i <=n-1 ; ++i) {
ans.push_back({i+1,i});
}
}
else{
for (int i = 0; i <5 ; ++i) {
ans.push_back({idxmi,idxmi});
}
for (int i = 1; i <=n ; ++i) {
if(g[i]>=0){
ans.push_back({i,idxmi});
}
}
for (int i = n; i >1 ; --i) {
// cout<<i-1<<' '<<i<<endl;
ans.push_back({i-1,i});
}
}
}
else {
if(zheng<=12){
for (int i = 1; i <=n ; ++i) {
if(g[i]>=0){
// cout<<i<<' '<<idxma<<endl;
ans.push_back({i,idxmi});
}
}
for (int i = n; i >1 ; --i) {
// cout<<i-1<<' '<<i<<endl;
ans.push_back({i-1,i});
}
}
else{
for (int i = 0; i <5 ; ++i) {
ans.push_back({idxma,idxma});
}
for (int i = 1; i <=n ; ++i) {
if(g[i]<0){
ans.push_back({i,idxma});
}
}
for (int i = 1; i <=n-1 ; ++i) {
ans.push_back({i+1,i});
}
}
}
cout<<ans.size()<<endl;
for (auto i:ans) {
cout<<i.first<<' '<<i.second<<endl;
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
}
题意:给n张牌,每张牌的价值是$ai$,刚开始除了第一张,每一张牌都上锁了,在开锁的牌里选一张,进行操作,操作有两种,第一种是解锁V个没有解锁的牌,从上往下依次,第二种操作是ans+=V;问答案的最大值是多少
思路:我们可以发现,解锁的牌数和价值是等价的,比如 $2 4 5 0 1$,当你解锁3张牌时,你的答案就是$2+4+5-(2-0)=9$,这就是最大,假设用掉了x张牌,就说明x张牌都是解锁的花了(x-1)的点数去解锁,剩下的就是贡献,即是$ans=sum-(x-1)$(第一张牌不用解锁),sum为前缀和,我们的做法是去枚举ans取最大即可,即是枚举x
:即是用DP求每一张牌的状态x,由于DP是n^2,所有我们用bitset表示状态,例如2 4 5 0 1,bt状态为1 0 0 0 0,代表刚开始只有第一张牌是解锁的,那么我们就可以操作2求一遍ans,然后我们进行操作1,那么我们的bt状态就变成了0 0 1 0 0 ,1前面的都是解锁了的,当我们遍历到idx=1时,我们发现,这时不用更新ans,因为你如果对idx=1的位置进行操作2,其实在idx=2的位置进行操作2时就已经包括了,在3时更新明显更优,那么在idx=1时由于bt[1]=0我们只有一种操作,就是对他进行操作1,那么我们的bt就变成了0 0 1 0 0 0 1,然后遍历到2时发现,idx=1,那么我们对他进行操作2,更新ans,然后进行操作1,因为对idx=1时,他可以不进行操作1,也可以进行操作1,那么idx=2进行操作1时,就会产生两种情况,bt就变成了0 0 0 0 0 0 1 1 0 0 1,变成了这种情况,最后两个1即是新产生的两种情况,依次类推,每一个1都代表了一种独立的情况,这些1的位置最多是在2 * n-1的位置,在大于n时,其实就代表了最后解锁时你剩余的牌数小于这个值V,这样也符合题意,我们得到的新的1会溢出,遍历到1时,我们更新,是正确的。
diamond:
#include<iostream>
#include<string>
#include<cstdio>
#include<bitset>
using namespace std;
#define debug 0
const int maxn = 200010;
#define ll long long
int n;
int a[maxn];
//ll dp[maxn];
bitset<maxn> dp;
void solve() {
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
n <<= 1; // 2倍
ll ans = 0, sum = 0;
dp[0] = 1;
for (int i = 0; i < n; ++i) {
dp |= (dp << a[i]);
sum += a[i];
if (dp[i] == 1) {
ans = max(ans, sum - i);
dp[i] = 0;
}
}
printf("%lld\n", ans);
}
int main() {
int t = 1;
// scanf("%d", &t);
while (t--) {
solve();
}
}