A. Dalton the Teacher
思路:签到题
记录当前值和下标相等的个数res,然后输出(res+1)/2即可
#include <iostream>
#include <cstring>
#include <algorithm>
#include<tuple>
#include <vector>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <cmath>
#include<functional>
using namespace std;
const int N =2e6+7,mod=998244353;
#define rep(i,a,n) for(int i=a;i<=n;i++)
typedef pair<int, int> PII;
typedef long long LL;
int n,m,k;
int a[N];
void solve(){
cin>>n;
rep(i,1,n)cin>>a[i];
long long res=0;
rep(i,1,n)if(i==a[i])res++;
cout<<(res+1)/2<<endl;;
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
B. Longest Divisors Interval
思路:连续2个数字里边必定有能整除2的,连续3个数字里边必定有能整除3的,…….连续n个数字里边必定有能整除n的,所以只需要从1开始判断直到不能被整除为止,这个数字好像最大才四十几
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
if(n%2){
cout<<1<<'\n';
continue;
}
int ans=1,now=2;
for(int i=2;i<=n;i++){
if(n%i==0){
ans++;
//n/=i;
}else break;
}
cout<<ans<<'\n';
}
return 0;
}
C1. Dual (Easy Version)
思路:构造题
我们可以找到数组里面绝对值最大的值进行跟新其他点的值,并将最大值进行跟新,如果最大绝对值是正数,正向遍历即可。如果最大绝对值是负数,反向遍历即可
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <cmath>
using namespace std;
const int N =2e5+7,mod=998244353;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define dep(i,a,n) for(int i=n;i>=a;i--)
typedef pair<int, int> PII;
typedef long long LL;
int n,m,k;
int a[N],I[N],J[N];
void solve(){
cin>>n;
k=0;
int mx=-2000,id1;
rep(i,1,n){
cin>>a[i];
if(mx<abs(a[i])){
mx=abs(a[i]);
id1=i;
}
}
int k=0;
if(a[id1]<0){
mx=a[id1];
dep(i,1,n-1){
while(a[i]>a[i+1]){
a[i]+=mx;
I[k]=i;
J[k]=id1;
k++;
if(a[i]<mx){
mx=a[i];
id1=i;
}
}
}
cout<<k<<endl;
rep(i,0,k-1)cout<<I[i]<<" "<<J[i]<<endl;
return ;
}
for(int i=1;i<n;i++){
while(a[i]>a[i+1]){
I[k]=i+1;
J[k]=id1;
k++;
a[i+1]+=mx;
if(a[i+1]>mx){
mx=a[i+1];
id1=i+1;
}
}
}
cout<<k<<endl;
rep(i,0,k-1)cout<<I[i]<<" "<<J[i]<<endl;
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
C2. Dual (Hard Version)
思路:这道题比前面一道限制能操作次数更低了,这题我分了三种情况
① 当数组里面全为正数:我们直接正向遍历一遍,把前面加到后面即可
② 当数组里面全为负数:我们直接反向遍历一遍,把后面的加到前面即可
③ 当数组里面既有负数又正数:
(1)我们尝试用绝对值最大的负数更新最大值,然后将数组全变为负数,然后可以在用第二种情况
(2)我们尝试用绝对值最大的正数更新最大值,然后将数组全变为正数,然后可以在用第一种情况
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
const int N=2e6+10,M=2e5;
typedef double db;
typedef pair<int,int>pii;
int n,m,k,Q,cnt,mx,mn;
vector<int>del;
int a[200010],b[200010],x[200010],y[200010];
int prime[N];
bool st[N];
void solve(){
cin>>n;
mx=mn=1;
rep(i,1,n){
cin>>a[i];
if(a[i]>a[mx])mx=i;
if(a[i]<a[mn])mn=i;
}
int tmp=a[mn],tot=0;
//全为非负数
if(a[mn]>=0){
cout<<n-1<<endl;
rep(i,1,n-1)cout<<i+1<<" "<<i<<endl;
return ;
}
//全为非正数
if(a[mx]<=0){
cout<<n-1<<endl;
per(i,2,n)cout<<i-1<<" "<<i<<endl;
return ;
}
//用绝对值最大的负数更新最大值
while(-a[mn]<a[mx])a[mn]*=2,x[++tot]=mn,y[tot]=mn;
rep(i,1,n)if(a[i]>0)x[++tot]=i,y[tot]=mn;
//判断负数更新是否可行
if(tot+n-1<=31){
cout<<tot+n-1<<endl;
rep(i,1,tot)cout<<x[i]<<" "<<y[i]<<endl;
per(i,2,n)cout<<i-1<<" "<<i<<endl;
return ;
}
else{
a[mn]=tmp;tot=0;
while(-a[mn]>a[mx])a[mx]*=2,x[++tot]=mx,y[tot]=mx;
rep(i,1,n)if(a[i]<0)x[++tot]=i,y[tot]=mx;
cout<<tot+n-1<<endl;
rep(i,1,tot)cout<<x[i]<<" "<<y[i]<<endl;
rep(i,1,n-1)cout<<i+1<<" "<<i<<endl;
}
}
signed main(){
int t;cin>>t;
while(t--)solve();
}
D. Earn or Unlock
思路:注意卡牌若用于激活后面的牌就不能计数了。
考虑朴素 dp:dpi,j 表示操作到第 i 张牌,已经解锁了后面 j 张牌的状态是否存在。则朴素转移的复杂度是 O(n2),而又因为状态的值只有 0,1 两种情况,容易联想到 bitset 进行优化,滚掉第一维(感觉确实不太会用bitset)
(学习bitset卡常小技巧bushi)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
ll a[N], s[N], n, ans;
bitset<N*2> f; //f[i][j]: 操作到i,已经解锁了后面j张牌,滚掉第一维
int main () {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i], s[i] = s[i-1] + a[i];
f[a[1]] = 1, f[0] = 0, ans = a[1]; //至少拥有第一张牌
for (int i = 2; i <= n; i++) {
if (f[i-1]) ans = max (ans, s[i] - (i - 1)); //把值为i-1的那张用来unlock的牌拿走了
f |= f << a[i];
f[i-1] = 0; //操作之后把上一张牌拿走了
//cout << ans << ' ';
}
//cout << ans << ' ';
//for (int i = 0; i < 10; i++) cout << f[i];
for (int i = n; i < n * 2; i++) { //从n开始
if (f[i]) ans = max (ans, s[n] - i);
}
cout << ans;
}
//把bitset看成一个字符串