法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;
}
//解法:排序加贪心
#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;
}
#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;
}
#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;
}
#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;
}
//本题需要找到合并阶乘的规律
//如果题目中没有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;
}
法1:爆搜
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
const int mod=998244353;
int aa[N];
int dp[N][46];
int ans=0;
int n,m;
void dfs(int dep,int a,int b,int c,int d,int e){//表示现在正在看第dep位
if(dep==n+1){
if(a+b+c+d+e<=m)ans=(ans+1)%mod;//这句要放在里面
return ;
}
if(a+b+c+d+e>m)return ;
for(int i=aa[dep];i<10;i+=2){
dfs(dep+1,b,c,d,e,i);
}
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++)aa[i]=(i%2==1);//奇数位置都设为1
for(int i=aa[1];i<10;i+=2){
for(int j=aa[2];j<10;j+=2){
for(int h=aa[3];h<10;h+=2){
for(int k=aa[4];k<10;k+=2){
for(int l=aa[5];l<10;l+=2){
dfs(6,i,j,k,h,l);
}
}
}
}
}
cout<<ans;
return 0;
}
//对于结点i,本题如果能找到i的最左孩子和最右孩子的下标,便可以迎刃而解
//对于第i个结点,其前面有i-1个结点,每个结点各有m个孩子,再加上1号结点+1就是左孩子
//可得第i个结点的最左孩子下标为(i-1)*m+2
//同理可得第i个结点的最右孩子下标为i*m+1(前i个结点各有m个孩子,再加上1号结点)就是右孩子
//故对于子树根结点,只需逐层累加最右孩子-最左孩子即可
//只需要处理最后一层的特殊情况:
//1、最左孩子下标超出n,出说明子树在最后一层没有结点,直接退
//2、最右孩子下标超出n,说明子树在最后一层的结点是非满的,将最右孩子下标改为n,累加后退出
//有1e5组询问,对于每组询问,可在近似logm n的时间复杂度内得出结果,不会超时
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
const int N=1e5+10;
const int mod=998244353;
int aa[N];
int dp[N][46];
int ans=0;
//第i层有m^(i-1)个结点 从(m^(i-1)+1) /2开始
void solve(){
int n,m,k;cin>>n>>m>>k;
int cnt=1;
int lchild=k;
int rchild=k;
while(1){
bool flag=0;
lchild=(lchild-1)*m+2;
rchild=rchild*m+1;
if(lchild>n)break;//左孩子超出直接跳
if(rchild>=n){//最右孩子超出n
flag=1;//这是最后一次
rchild=n;//改为n
}
cnt+=rchild-lchild+1;
if(flag)break;
}
cout<<cnt;
return ;
}
signed main(){
int t=1;cin>>t;
while(t--)solve();
return 0;
}