AcWing 4965. 三国游戏 - AcWing
法1:dfs的时间复杂度是2^n 对于每一个我们有选与不选两种
//法1:dfs
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int, int> PII;const int N=1e5+7;
int n;
int a[4][N];
int x,y,z;
int ans=0;
int len=0;
void dfs(int dep){if(x>(y+z)||y>(x+z)||z>(y+x)){ans=max(len,ans);}if(dep==n+1)return ;x+=a[1][dep];y+=a[2][dep];z+=a[3][dep];len++;dfs(dep+1);len--;x-=a[1][dep];y-=a[2][dep];z-=a[3][dep];dfs(dep+1);return ;
}
void solve(){cin>>n;for(int i=1;i<=n;i++)cin>>a[1][i];for(int i=1;i<=n;i++)cin>>a[2][i];for(int i=1;i<=n;i++)cin>>a[3][i];dfs(1);cout<<(ans==0?-1:ans);return ;
}
signed main(){int t=1;while(t--)solve();return 0;
}
法2:分三个国家赢的情况讨论
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N], c[N], t[N], n;
//t[i]计算差值
int get(int x[], int y[], int z[]) {for (int i = 1; i <= n; i ++) {t[i] = x[i] - y[i] - z[i];}sort(t + 1, t + 1 + n, greater<>());//大的在左边for (int i = 1; i <= n; i ++) {t[i] += t[i - 1];//加上这个数if (t[i] <= 0) return i - 1;//如果和小于等于0的话那么就不行了 返回上一个最后>0的长度 i-1}return n;//一直没有返回那么全部都符合条件
}
signed main () {cin >> n;for (int i = 1; i <= n; i ++) cin >> a[i];for (int i = 1; i <= n; i ++) cin >> b[i];for (int i = 1; i <= n; i ++) cin >> c[i];int res = max({get(a, b, c), get(b, a, c), get(c, a, b)});//max可以用于数组判最大cout << (res == 0 ? -1 : res) << '\n';return 0;
}
5395. 平均 - AcWing题库
//解法:排序加贪心
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int, int> PII;
const int N=1e5+7;
int n;
vector<int>v[10];
int num[10];//记录每个数出现的次数
void solve(){cin>>n; int sur=n/10;for(int i=1;i<=n;i++){int a,b;cin>>a>>b;v[a].push_back(b);num[a]++; }int ans=0;for(int i=0;i<=9;i++)sort(v[i].begin(),v[i].end());for(int i=0;i<=9;i++){if(num[i]>sur){int temp=num[i]-sur;//多出来temp个数需要改ans+=accumulate(v[i].begin(),v[i].begin()+temp,0);//注意后面的这个位置到不了 0-(temp-1)这是temp个数 }}cout<<ans;return ;
}
signed main(){int t=1;while(t--)solve();return 0;
}
4967. 翻转 - AcWing题库
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int, int> PII;
const int N=1e5+7;
int n;
vector<int>v[10];
int num[10];//记录每个数出现的次数
char change(char ch){if(ch=='1')return '0';return 1;
}
void solve(){string t,s;cin>>t>>s;//把s变成t int len=t.size();if(s[0]!=t[0]||s[len-1]!=t[len-1]){cout<<-1<<'\n';return ;}//特判一下int cnt=0;for(int i=1;i<len-1;i++){if(s[i]!=t[i]){if(s[i-1]==s[i+1]&&s[i-1]!=s[i]&&s[i-1]==t[i]){cnt++;s[i]=change(t[i]);}else{cout<<-1<<'\n';return ;}}}cout<<cnt<<'\n';return ;
}
signed main(){int tt=1;cin>>tt;while(tt--)solve();return 0;
}
154. 滑动窗口 - AcWing题库
#include <iostream>
using namespace std;
const int N = 1000010;
int a[N], q[N], hh=1, tt = 0;
//q[i]用来存下标
//一般hh设在第一个元素 tt设在hh的前面一位
void getMinWindow(int n, int k) {for (int i = 1; i <= n; ++i) {cin >> a[i];//右端点是i 长度是k 左端点是i-k+1>q[hh]的时候while(tt>=hh&&i-k+1>q[hh])hh++;//队首元素出队while (hh <= tt && a[i] <= a[q[tt]]) --tt;//维护队首元素是最小值q[++tt] = i;if (i >= k) cout << a[q[hh]] << " ";//形成了一个窗口}cout << '\n';
}void getMaxWindow(int n, int k) {hh = 1; tt = 0;for (int i = 1; i <= n; ++i) {while(tt>=hh&&i-k+1>q[hh])hh++;while (hh <= tt && a[i] >= a[q[tt]]) --tt;q[++tt] = i;if (i >= k) cout << a[q[hh]] << " ";}
}int main() {int n, k;cin >> n >> k;getMinWindow(n, k);getMaxWindow(n, k);return 0;
}
4964. 子矩阵 - AcWing题库
#include<iostream>
#include<cstring>
using namespace std;
const int N=1010,mod=998244353;
int g[N][N],min1[N][N],min2[N][N],max1[N][N],max2[N][N];
int n,m,a,b;void getmin1(int id){int q[N],tt=-1,hh=0;for(int i=1;i<=m;i++){while(tt>=hh&&i-k+1>q[hh])hh++;//队首元素的下标<窗口左端点时候while(tt>=hh&&g[id][q[tt]]>=g[id][i])tt--;q[++tt]=i;//维护每一行的最小值if(i>=b)min1[id][i]=g[id][q[hh]];//形成了一个窗口}
}void getmin2(int id){int q[N],tt=-1,hh=0;for(int i=1;i<=n;i++){while(tt>=hh&&i-q[hh]+1>a)hh++;while(tt>=hh&&min1[q[tt]][id]>=min1[i][id])tt--;q[++tt]=i;//对于min1数组维护每一列的最小值 就得到了这个区间的最小值min1[i][j]就是以第i行第j列为右端点时候的最小值if(i>=a)min2[i][id]=min1[q[hh]][id];}
}void getmax1(int id){int q[N],tt=-1,hh=0;for(int i=1;i<=m;i++){while(tt>=hh&&i-q[hh]+1>b)hh++;while(tt>=hh&&g[id][q[tt]]<=g[id][i])tt--;q[++tt]=i;if(i>=b)max1[id][i]=g[id][q[hh]];}
}void getmax2(int id){int q[N],tt=-1,hh=0;for(int i=1;i<=n;i++){while(tt>=hh&&i-q[hh]+1>a)hh++;//超过了要出队while(tt>=hh&&max1[q[tt]][id]<=max1[i][id])tt--;q[++tt]=i;if(i>=a)max2[i][id]=max1[q[hh]][id];}
}int main(){scanf("%d%d%d%d",&n,&m,&a,&b);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&g[i][j]);for(int i=1;i<=n;i++) getmin1(i);for(int i=b;i<=m;i++)getmin2(i);for(int i=1;i<=n;i++)getmax1(i);for(int i=b;i<=m;i++)getmax2(i);long long res(0);for(int i=a;i<=n;i++)for(int j=b;j<=m;j++) res+=((long long)min2[i][j]*max2[i][j])%mod,res%=mod;
//不断队mod取模printf("%d\n",res);return 0;
}
5021. 阶乘的和 - AcWing题库
//本题需要找到合并阶乘的规律
//如果题目中没有A[i]阶乘加和的条件,那么m就是数组A中的最小值
//而如果要对A[i]的阶乘加和,可能出现两个较小的数的阶乘合并成一个较大数的阶乘的现象
//如3个2的阶乘可以合并成3的阶乘,4个3的阶乘可以合并成4的阶乘
//故得到规律:若数字num出现了cnt次,且num可以被(cnt+1)整除,那么就可以合并成(num+1)的阶乘
//如样例中的2 2 2,可以将其合并成一个3,转化为数字3出现了一次
//用map容器存储<数字,出现的次数>,再逐个数字验证是否满足如上规律,
//若满足则合并,并更新其出现的次数,若有不满足的数字则直接输出即可
//元素个数不能超过1e5那么 最大可以被凑出来的阶乘就是100000!
//若所有数都大于1e5那么能整除的就只能是其中最小的
//对于x>=k 则x!一定可以被k!整除 反之则不行
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
map<ll,int>mp;//这个数字和这个数字出现的次数
int main(){int n;scanf("%d",&n);for(int i=1;i<=n;i++){ll tmp;scanf("%lld",&tmp);mp[tmp]++;//用map记录每个数字出现的次数 } map<ll,int>::iterator it;for(it=mp.begin();it!=mp.end();it++){//自动按照元素从小到大的顺序遍历 ll num=it->first;//取出当前元素 int cnt=it->second;//取出当前元素出现的次数 if(cnt%(num+1)==0){//满足阶乘合并的条件 mp[num+1]+=cnt/(num+1);//例如3个2的阶乘合并成1个3的阶乘,3的出现次数加1 num+1出现的次数加上cnt/(num+1)}else{printf("%lld\n",num);//否则到此为止,不能再合并阶乘,当前(最小)元素就是要找的m return 0;}}return 0;
}
5391. 奇怪的数 - AcWing题库
4971. 子树的大小 - AcWing题库
5394. 反异或01串 - AcWing题库