2023牛客多校

D

n × m 的巧克力,Kelin 先手 Walk Alone 后手拿走一块矩形的巧克力,谁拿 走 (n, m) 处的巧克力谁输,问结果。 数据范围:1 ≤ n, m ≤ 109。

只要全是奇数WA就赢

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,m;
    cin>>n>>m;
    if(n%2==1&&m%2==1)
        cout<<"Walk Alone";
    else
        cout<<"Kelin";
}

J

Walk Alone 初始有 n 块钱,如果每次投 x 元,有一半的概率输掉这 x 元,另 一半概率赢得 2x 元。现在 Walk Alone 采取下述策略投注: 如果上一把赢了,这一把投 xi = 1 ,如果上一把输了,这一把投 xi = 2xi−1 元。 问 Walk Alone 有多大概率拿到 n + m 元离开。 1 ≤ n, m ≤ 109。

队友写的,基本没看

#include<bits/stdc++.h>
using namespace std;
const long long  num=998244353;
long long ksm(long long a,long long b)
{
    long long ans=1;
    while(b){
        if(b&1) ans=ans*a%num;
        a=a*a%num;
        b/=2;
    }
    ans%=num;
    return ans;
}
int main()
{
    long long n,m,i,f,l;
    long long a=1,b=1;
    cin>>n>>m;
    f=ceil(log(n+1)/log(2));
    l=floor(log(n+m+1)/log(2))-1;
    if(l-f==-2){
        a=ksm((ksm(2,(f+l)/2)-1),m)%num;
        b=ksm((ksm(2,(f+l)/2)),m)%num;
    }
    else{
        i=f;
        while(i<=l){
            a=a*ksm((ksm(2,i)-1),ksm(2,i))%num;
            b=b*ksm((ksm(2,i)),ksm(2,i))%num;
            i++;
        }
        a=a*ksm((ksm(2,f-1)-1),pow(2,f)-1-n)%num;
        b=b*ksm((ksm(2,f-1)),pow(2,f)-1-n)%num;
        a=a*ksm((ksm(2,l+1)-1),m+n-pow(2,l+1)+1)%num;
        b=b*ksm((ksm(2,l+1)),m+n-pow(2,l+1)+1)%num;
    }
//     cout<<3*ksm(4,num-2)%num<<endl;
    cout<<a*ksm(b,num-2)%num;
}

给定一个无向图 G(n, m),可以将其中任意一条边分裂成一条长度为任意的 链(向边中插任意多个点),可以操作任意多次(也可以不操作)。问经过这 样处理之后,从 1 号节点出发,至多走 k 步最多可以到多少个节点。 数据范围:1 ≤ n ≤ 105,1 ≤ m ≤ 2 × 105,1 ≤ k ≤ 109。

我们可以确定的是1和到1的最短距离小于等于k的是满足条件的,要通过增加节点数量来最大ans,肯定是选择加在靠后的位置上,因为越靠后影响到的其他节点越少,那么我们的节点可以选择加在不会对其他节点产生影响的边上。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<int>edge[100005];
ll du[100005];//每个节点的度
ll dis[100005];//每个节点到1节点的最短路
bool flag[100005];//标志位
ll n,m,k;
void bfs()
{
    queue<int>q;
    q.push(1);
    dis[1]=0;
    flag[1]=1;
    while(!q.empty())
    {
        auto u = q.front();
        q.pop();
        for(auto v :edge[u])
        {
            if (flag[v]==0) {
                dis[v] = dis[u] + 1;
                q.push(v);
                flag[v]=1;
            }
        }
    }
}
vector<int>tree[100005];
ll du_tree[100005];
void dfs(int f,int s,ll d)//节点 深度
{
    if(d>k||flag[s]||dis[f]>=dis[s])
        return ;
    du_tree[f]++;
    du_tree[s]++;
    tree[f].push_back(s);
    tree[s].push_back(f);
    flag[s]=1;
    for(auto v:edge[s])
    {
        dfs(s,v,d+1);
    }
}
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin>>a>>b;
        edge[a].push_back(b);
        edge[b].push_back(a);
        du[a]++;
        du[b]++;
        dis[a]=dis[b]=0x3f3f3f;
    }
    //bfs求最小路
    bfs();
//     for(int i=1;i<=n;i++)
//         cout<<du[i]<<' ';
    //根据最短路建立删去个别边的树
    for(int i=1;i<=n;i++) flag[i]=0;
    for(auto v:edge[1]) dfs(1,v,1);
//     for(int i=1;i<=n;i++)
//     {
//         cout<<du_tree[i]<<' ';
//         for(auto v:tree[i])
//             cout<<v<<' ';
//         cout<<endl;
//     }
    long long ans=0;
    queue<int>p;
    p.push(1);
    while(!p.empty())
    {
        auto u = p.front();
        if(dis[u]<=k)//此节点到1的距离小于等于k满足条件
            ans=ans+1;
        if(du[u]==1&&u!=1)
            ans=ans+(k-dis[u]);
        else if(du[u]!=du_tree[u]&&dis[u]<k&&u!=1)
        {
            ans=ans+(k-dis[u])*(du[u]-du_tree[u]);
        }

        p.pop();
        for(auto v:tree[u])
        {
            if(dis[u]<dis[v])
                p.push(v);
        }
    }
     cout<<ans<< '\n';
}

H

照着题解写的

2023多校第一场HJKL讲题视频+知识点讲解-逆元、扩展欧几里得、扩展中国剩余定理_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1TV411j7eJ/?vd_source=565c4ab0ce1287591cb1410a51345bac

#include <bits/stdc++.h>
using namespace std;
struct on{
    int l,r;//左右边界
    bool tmp;//正向or逆向
};
int n,a[1000010],b[1000010];
vector<on> s;
bool cmp(on x,on y)
{
    return x.l<y.l;
}
long long sum=0,ans=0;
int R[2];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    for(int i=1;i<=n;i++)
    {
        if(a[i]<b[i])s.push_back((on){a[i],b[i],0});
        if(a[i]>b[i])s.push_back((on){b[i],a[i],1});
        sum+=abs(a[i]-b[i]);
    }
    sort(s.begin(),s.end(),cmp);
    R[0]=R[1]=-1e9;//正向和反向的右端点
    for(auto i:s){
        ans=max(ans,1LL*min(i.r,R[i.tmp^1])-i.l);
        R[i.tmp]=max(R[i.tmp],i.r);
    }
    printf("%lld",sum-2*ans);
}

M

给两个容积分别为 A,B 的水杯,每次可以执行以下的四种操作之一:
        把其中一个水杯装满水。
        把其中一个水杯中的全部水倒掉。
        把其中一个水杯中现有的水全部喝完。
        把一个杯子中的水尽可能转移到另一个水杯中,水不溢出。
为让懵哥喝掉恰好 x 体积的水,问最少要操作几次。 T 组询问,1 ≤ T ≤ 105,1 ≤ A,B ≤ 109。

对于水杯A来说可以表示成XaA+YaB同理B杯可以是XbA+YbB
装水 :(Xa,Ya)->(1,0)   (Xb,Yb)-->(0,1)
喝水:                 (0,0)                   (0,0)      w+=(XaA+YaB)
倒水 :                  (0,0)                    (0,0)
转移: A——>B  
        if(A中的水+B中的水<=B可以装的水)//A能完全倒入
                (Xa,Ya)->(0,0)    (Xb,Yb)->(Xa+Xb,Ya+Yb)
        else
                 (Xa,Ya)->(Xa+Xb,Ya+Yb-1)    (Xb,Yb)->(0,1)

由上面可以发现x=rA+sB,通过裴蜀定理可以判断是否有解,在利用拓展欧几里得计算r和s。若r>=0&&s>=0,那肯定是一直倒倒倒喝喝喝,ans=2*(r+s);如果是r>0&&s<0,那我们需要先装A,再倒入B里如果满了,就倒掉(最后一个不用倒,因为那时候只要把A喝了就可以),装满过s个B杯

#include<bits/stdc++.h>
using namespace std;
#define mode 1
#define ll long long
ll exgcd(ll a, ll b, ll &x, ll &y){
	if(!b){
		x = 1, y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, y, x);
	y -= a / b * x;	
	return d;
}
ll a,b,x;
ll ans;
ll getmin(ll t,ll r,ll s)
{
    ll n = r + t * b, m = s - t * a;
    if(n >= 0 && m >= 0) ans = min(ans, 2 * (n + m));
    else ans = min(ans, 2 * (abs(n)+abs(m)) - 1);
    return ans;
}
void isok()
{
    ans=1e18;
    cin>>a>>b>>x;
    ll r,s;
    ll c=exgcd(a,b,r,s);
    if(x%c)
    {
        cout << -1 << endl;
        return ;
    }
    cout<<r<<' '<<s<<endl;
    a/=c;b/=c;x/=c;
    r*=x;s*=x;
    cout<<r<<" "<<s<<endl;
    // 附近找最小值
    ll t0=-r/b;
    for (ll t=t0-2;t<=t0+2;++t) ans=getmin(t,r,s);
    t0=s/a;
    for (ll t=t0-2;t<=t0+2;++t) ans=getmin(t,r,s);
    cout<<ans<<endl;
}

int main()
{
    int t;
    if(mode) cin>>t;
    else t=1;
    while(t--)
        isok();
}

I

怎么摆放o和x是五子棋平局,每行4个4个交替放就可以了。

#include<bits/stdc++.h>
using namespace std;
void isok()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n-1;i++)
    {
        for(int j=0;j<m;j++)
        {
            if((i+j/4)%2==0)
                cout<<'o';
            else 
                cout<<'x';
        }
        cout<<endl;
    }
    if(n%2==0)
        for(int j=0;j<m;j++)
        {
            if((n-1+j/4)%2==0)
                cout<<'o';
            else 
                cout<<'x';
        }
    else
        for(int j=0;j<m;j++)
            if(j%2==0)
                cout<<'x';
            else cout<<'o';
    cout<<endl;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
        isok();
}

 E

找一个y使得y^2的前缀有x

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
//x<=y*y/10^k<x+1
//sqrt(x*10^k)<=y<sqrt((x+1)*10^k)
//y<=1e9->k<=9
void isok()
{
    ll x;
    cin>>x;
    ll t=(ll)sqrt(x);
    if(t*t==x)
    {
        cout<<t<<endl;
        return ;
    }
    int k=0;
    ll p=1;//p=10^k
    while(1)
    {
        for(ll i=sqrt(x*p);i<=sqrt(x*p)+1;i++)
        {
            if(i*i/p==x&&i<=1e9)
            {
                cout<<i<<endl;
                return ;
            }
        }
        k++;
        if(k>9)
            break;
        p*=10;
    }
    cout<<-1<<endl;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
        isok();
}

K

i上不盖盖子那么f[i][0]=max(f[i-1][0],f[i-1][1]。
i这个位置如果有盖子我们有三个选择:
        1.盖i上                            f[i][1]=f[i][0]+a[i];
        2.盖i+1上                        f[i+1][1] = max(f[i][0],f[i][1])+a[i+1];
        3.盖i-1上                         f[i][0]=max(f[i][0],f[i-1][1]);
在dp的时候先转移2再转移1最后是3,原因:我们如果先算1那f[i][1]的盖子是i上的盖子就不能再放上i+1了,先算2的话i上的盖子是i-1的。最后算3同理

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[1000005];
bool b[1000005];
ll f[1000006][2];//前i个当前位置i是否盖盖子
int main()
{
    int n;
    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++)
    {
        f[i][0] = max(f[i-1][0],f[i-1][1]);
        if(b[i] == 1)
        {
            f[i+1][1] = max(f[i][0],f[i][1])+a[i+1];
            f[i][1] = f[i][0]+a[i];
            f[i-1][1]=f[i-1][0]+a[i-1];
            f[i][0]=max(f[i][0],f[i-1][1]);
        }
    }
 
    cout << max(f[n][0],f[n][1]);
}

D

n个人m个菜轮流选k个菜使得每个人对菜品的满意度之和最大
以两个人为例 A  100  50    B  2  0  A肯定选2让B来选1,也就是说会把自己最喜欢的也是让后面的人最喜欢的,那自己选次喜欢的,这样自己最喜欢的和次喜欢的都有了。对于最后一个人肯定是选目前有的菜里最喜欢的菜。那就倒着选菜。

/*

12 25 24 2 23 1 7 17 10 13 9 4 0 29 11 20 14 27 19 18
9 1 22 26 15 16 11 0 18 24 3 21 25 6 19 7 14 13 17 28
26 27 16 2 17 20 12 4 3 1 24 19 9 28 8 18 15 0 13 22

*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct on{
    ll love;
    int num; 
}A[2002][2002];
bool cmp(on a,on b)
{
    return a.love>b.love;
}
void isok()
{
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            ll l;
            cin>>l;
            A[i][j].love=l;
            A[i][j].num=j;
        }
    set<int>ans;
    for(int i=1;i<=n;i++)
        sort(A[i]+1,A[i]+1+m,cmp);
//     for(int i=1;i<=n;i++)
//     {
//         for(int j=1;j<=m;j++)
//         {
//             cout<<A[i][j].love<<" ";
//         }
//         cout<<endl;
//     }   
    bool flag[2002];// 能不能买 能1
    for(int i=1;i<=m;i++)
        flag[i]=1;
    for(int i=(k-1)%n+1;k>0;k--)
    {
        for(int j=1;j<=m;j++)
        {
            if(flag[A[i][j].num])
            {
                //cout<<A[i][j].num<<' ';
                flag[A[i][j].num]=0;
                ans.insert(A[i][j].num);
                break;
            }
        }
        i--;
        if(i==0)
            i=n;
    }
    for(auto s:ans)
        cout<<s<<' ';
    cout<<endl;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
        isok();
}

G

马拉车

换行还是'\n'好,endl狠狠的超时了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define io  ios::sync_with_stdio(false);cin.tie(NULL)
/*
	string s="AAABBCCAAA";
	Manacher ma(s);
	for(int i=1;i<ma.n;i++)
		cout<<ma.len[i];
*/
struct Manacher{
	string s;
	int n;
	string Ma_s;
	vector<int> len;
	Manacher(string s) : s(s),n(s.size()*2+3)
    {
		init(Ma_s);
		build(len);
	}
	void init(string &str)
    {
		str="$#";
		for(auto &i : s)
        {
			str+=i;
			str+='#';
		}
		str+='@';
	}
	void build(vector<int> &len)
    {
        auto check = [&](char l,char r)
        {
            if(l=='#' && r=='#') return 1;
            if(l=='o' || l=='s' || l=='x' || l=='z')
            {   
                if(l==r) return 1;
                else return 0;
            }
            if(l=='b' && r=='q') return 1;
            if(l=='d' && r=='p') return 1;
            if(l=='n' && r=='u') return 1;
            if(r=='b' && l=='q') return 1;
            if(r=='d' && l=='p') return 1;
            if(r=='n' && l=='u') return 1;
            return 0;
        };
		len=vector<int>(n,0);
		int l=1 , r=1 , p=1;
		for(int i=2;i<=n-3;i++)
        {
            if(!check(Ma_s[i],Ma_s[i])) continue;
			if(i>r)
            {
				l = r = p = i;
				while(check(Ma_s[l-1],Ma_s[r+1]))
					l--,r++;
				len[i] = r - p;
			}
			else
            {
				len[i] = len[2*p-i];
				if(i+len[i]>=r)
                {
					p = i;
					l = 2 * p - r;
					while(check(Ma_s[l-1],Ma_s[r+1]))
						l--,r++;
					len[i] = r - p;
				}
			}
		}
	}
};
void isok()
{
    string s;
    cin>>s;
    for(auto i:s)
    {
        if(!(i=='o'||i=='s'||i=='x'||i=='z'||i=='b'||
           i=='q'||i=='d'||i=='p'||i=='n'||i=='u'))
        {
            cout<<"No\n";
            return ;
        }
    }
    Manacher ma(s);
    int n = s.size();
    int j = 1;
    for(int i=1;i<=n;i++)
    {
            int t = i - j + 1;
            if(ma.len[i+j]>=t) j = i + 1;
    }
    if(j>n) 
        cout<<"Yes\n";
    else 
        cout<<"No\n";
}
int main()
{
    io;
    int T;
    cin>>T;
    while(T--)
        isok();
}

A

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s1,s2;
    cin>>s1>>s2;
    long long i,x=0,y=0;
    if(s1=="0"&&s2!="0") cout<<-1;
    else{
        for(i=0;i<s1.size();i++) x=x*2+(s1[i]-'0');
        for(i=0;i<s2.size();i++) y=y*2+(s2[i]-'0');
        cout<<abs(x-y);
    }
}

H

给定长度为 n 的正整数序列 A 每次操作可以选定两个不相同的下标 i, j,
令 Ai ← Ai + 1, Aj ← Aj − 1
判断是否可以通过上述操作将 A 中的整数全部变成质数 1 ≤ n ≤ 1000

变成2 2 2 2 2 2 ......

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[1003];
bool fun(ll num)
{
    if (num <= 3)
        return num > 1;
    if (num % 6 != 1 && num % 6 != 5)
        return false;
    ll s = sqrt(num);
    for (ll i = 5; i <= s; i += 6)
        if (num % i == 0 || num % (i + 2) == 0)
            return false;
    return true;
}
ll sum;
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    if(n==1)
    {
        if(fun(a[1]))
            cout<<"Yes";
        else
            cout<<"No";
        return 0;
    }
    if(n==2)
    {
        ll s=a[1]+a[2];
        if(s<4)
        {
            cout<<"No";
            return 0;
        }
        if(s%2==0||fun(s-2))
            cout<<"Yes";
        else
            cout<<"No";
        return 0;
        
    }
    for(int i=1;i<=n-2;i++)
        sum-=2;
    if(sum<4)
        cout<<"No";
    else 
        cout<<"Yes";
}

D

给定 n × n 的 01–矩阵 A
A 的第 i 行从左到右依次连接,形成可能带前导零的二进制数 ri
A 的第 j 列从上到下依次连接,形成可能带前导零的二进制数 cj
次操作可以指定 A 的一行或一列,将其中的 0 和 1 翻转 问是否能达成 min(ri) ≥ max(cj),若能则求出最少操作次数 1 ≤ n ≤ 2000

#include<bits/stdc++.h>
using namespace std;
char A[2002][2002];
long long int sum[2002];
int main()
{
    int n,cnt1=0,cnt2=0;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            cin>>A[i][j];
        getchar();
    }
    for(int i=1;i<=n;i++)
    {
        bool x;
        if(A[1][1]==A[i][1])
            x=0,cnt1++;
        else
            x=1,cnt2++;
        for(int j=2;j<=n;j++)
        {
            if(x)
            {
                if(A[1][j]==A[i][j])
                {
                    cout<<-1;
                    return 0;
                }
            }
            else
            {
                if(A[1][j]!=A[i][j])
                {
                    cout<<-1;
                    return 0;
                }
            }
        }
    }
    int c0=0,c1=0;
    for(int i=1;i<=n;i++)
    {
        if(A[1][i]=='1')
            c1++;
        else
            c0++;
    }
    cout<<min(cnt1,cnt2)+min(c1,c0);
}

J

考虑 n 个编号分别为 1, . . . , n 的抽象物体构成的集合 G 及其上的关系
定义 G 上的一组排名 R 是一个 n 阶排列 定义 G 上的一组赢关系为有序对 〈u, v〉,其中 1 ≤ u, v ≤ n, u ̸= v 称排名 R 满足赢关系 〈u, v〉,当且仅当在 R 中 u 出现在 v 前面 给定 n 以及 m 组赢关系,构造最少组排名使得每组赢关系都被至少一 组排名所满足 2 ≤ n ≤ 106,1 ≤ m ≤ 106

数量不是1就是2,不能一次满足的就一次正序一次倒序就可以了

#include<bits/stdc++.h>
using namespace std;
vector<int>edge[1000005],v1;
queue<int> q0;
int in[1000005];
int main()
{
    int i,j,n,m,u,v,k=1,ans[1000005],l=0;
    cin>>n>>m;
    for(i=0;i<m;i++){
        cin>>u>>v;
        edge[v].push_back(u);
        in[u]++;
    }
    for(i=1;i<=n;i++){
        if(in[i]==0) q0.push(i);
    }
    while(!q0.empty()){
            v=q0.front();
            ans[l++]=v;
            q0.pop();
            for(auto b:edge[v]){
                in[b]--;
                if(in[b]==0) q0.push(b);
            }
    }
    if(n==l){
        cout<<1<<endl;
        for(i=l-1;i>=0;i--) cout<<ans[i]<<" ";
    }
    else{
        cout<<2<<endl;
        for(i=1;i<=n;i++){
            cout<<i<<" ";
        }
        cout<<endl;
        for(i=n;i>0;i--){
            cout<<i<<" ";
        }
        cout<<endl;
    }
}

E

队友说很简单,那我就不看了

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
vector<int>edge[500005];
queue<int>q;
bool flag[500005],ans=0;
int dis[5000005];
void bfs()
{
    q.push(1);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(auto v:edge[u]){
            if(dis[v]==inf){
                q.push(v);
                dis[v]=dis[u]+1;
            }
        }
    }
}
void dfs(int u)
{
    if(ans) return;
    flag[u]=1;
    for(auto b:edge[u]){
        if(!flag[b]&&!ans){
            if(dis[b]!=inf&&dis[b]!=dis[u]+1) ans=1; 
            dis[b]=dis[u]+1;
            dfs(b);
        }
    }
    flag[u]=0;
}
int main()
{
    int t,u,v,i,n,m;
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>t;
    while(t--){
        cin>>n>>m;
        for(i=1;i<=n;i++){
            dis[i]=inf;
            edge[i].clear();
        }
        ans=0;
        for(i=0;i<m;i++){
            cin>>u>>v;
            edge[u].push_back(v);
        }
        dis[1]=0;
        dfs(1);
        if(!ans) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}

F

题目大意
        n个人进行投票选举国王,每个人有互不相同的政治倾向 ai。
        投票进行 n − 1轮,每轮每个人投票选一个其他人,得票最多的人被淘汰。如果票 数相同 ai最大的人被淘汰。
        每轮每个人的策略如下: 投票给和自己ai之差绝对值最大的人j,如果有多个这样的人投给 aj最大的那个。
 

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,i,a[1000005],l=0,r,b[1000005];
    cin>>n;
    r=n-1;
    for(i=0;i<n;i++){
        cin>>a[i];
        b[i]=a[i];
    }
    sort(a,a+n);
    while(l<r){
        int mid=(a[r]+a[l])/2;
        if(upper_bound(a+l,a+r+1,mid)-(a+l)>=(r-l+2)/2) r--;
        else l++;
    }
    for(i=0;i<n;i++) if(a[l]==b[i]) cout<<i+1;
}

L

给定一个 n × m的灯阵,每次操作点亮/熄灭一行/一列的所有灯,问最 后亮着的灯的数量。

反着做

#include<bits/stdc++.h>
using namespace std;
const int num=1e6;
struct node{
    int x,flag;
}op[1000005];
bool flag[2000005];
int main()
{
    int n,m,q,i;
    long long ans=0;
    cin>>n>>m>>q;
    for(i=0;i<q;i++){
        string a,c;
        int b;
        cin>>a>>b>>c;
        if(a=="row"){
            op[i]={b,c=="on"?1:0};
        }
        if(a=="column"){
            op[i]={b+num,c=="on"?1:0};
        }
    }
    for(i=q-1;i>=0;i--){
        if(!flag[op[i].x]){
            if(op[i].x>num){
                if(op[i].flag) ans+=n;
                m--;
            }
            else{
                if(op[i].flag) ans+=m;
                n--;
            }
        }
        flag[op[i].x]=1;
    }
    cout<<ans;
}

A

题意:给定一个 01字符串t ,构造一个长度为 n的 01串 ,使得t 在m=t+s+t 中仅出现两次。

要么全0要么全1

#include<bits/stdc++.h>
using namespace std;
void isok()
{
    int n;
    cin>>n;
    bool flag1=1,flag2=1;
    string t,tt;
    cin>>t;
    tt=t;
    for(int i=1;i<=n;i++)
        t+='0';
    t+=tt;
    //判断tt只在t中出现在开头和结尾
    int len1=t.size();
    int k=tt.size();
    for(int i=1;i+k-1<len1-1;i++)
    {
        if(tt==t.substr(i,k))
        {
            flag1=0;
            break;
        }
    }
    if(flag1==1)
    {
        for(int i=1;i<=n;i++)
            cout<<0;
        cout<<endl;
        return ;
    }
    t=tt;
    for(int i=1;i<=n;i++)
        t+='1';
    t+=tt;
    for(int i=1;i+k-1<len1-1;i++)
    {
        if(tt==t.substr(i,k))
        {
            cout<<-1;
            return ;
        }
    }
    for(int i=1;i<=n;i++)
        cout<<1;
    cout<<endl;
    return ;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
        isok();
}

D

给定三个整数 k,c,n 求满足以下条件的有序对 (a,b) 的个数:ka+b=c ,b∣c ,gcd(a,b)>n

#include<bits/stdc++.h>
using namespace std;
#define ll long long
void  isok()
{
    ll k,c,n,ans=0;
    cin>>k>>c>>n;
    ll a,b;
    for(int i=1;i*i<=c;i++)
    {
        if(c%i==0)
        {
        if(i>=n)
        {
            b=i;
            a=(c-b)/k;
            if(a*k==(c-b)&&gcd(a,b)>=n&&a>=n)
                ans++;
        }
        if(c/i>=n)
        {
            b=c/i;
            a=(c-b)/k;
            if(a*k==(c-b)&&gcd(a,b)>=n&&a>=n)
                ans++;
        }
        }
    }
    cout<<ans<<endl;
}
int main()
{
    int q;
    cin>>q;
    while(q--){
        isok();   
    }
}

 G

记录1234出现的次数,每次找到一个满足的区间后对改区间进行判断,看l能不能向后移动

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i,n,k,a[100005],x=0,o=0,w=0,t=0,l=0,r=0,ans=100005;
    cin>>n>>k;
    for(i=0;i<n;i++){
        cin>>a[i];
    }
    for(r=0;r<n;r++){
        switch(a[r]){
            case 1:o++;break;
            case 2:w++;break;
            case 3:t++;break;
            case 4:x++;break;
        }
        if(x>=k&&o>0&&w>0&&t>0){
            while(x>=k&&o>0&&w>0&&t>0){
                switch(a[l]){
                    case 1:o--;break;
                    case 2:w--;break;
                    case 3:t--;break;
                    case 4:x--;break;
                }
                l++;
            }
            ans=min(ans,r-l+2);
        }
    }
    cout<<ans;
}

 A

#include<bits/stdc++.h>
using namespace std;
map<string,int> mp;
int main()
{
    int n,c,i,j,ans=0;
    cin>>n;
    cin>>c;
    string s;
    for(i=0;i<c;i++){
        cin>>s;
        mp[s]=1;
        if(mp[s]==n) ans++;
    }
    for(i=1;i<n;i++){
        cin>>c;
        for(j=0;j<c;j++){
            cin>>s;
            if(mp.count(s)) mp[s]++;
            if(mp[s]==n) ans++;
        }
    }
    cout<<ans<<endl;
    for(auto b:mp){
        if(b.second==n) cout<<b.first<<endl;
    }
}

J

考虑8个一组首尾差5那么每次加8这组头和上组尾的差就会使3

#include<bits/stdc++.h>
using namespace std;
int a[8]={0,3,6,1,4,7,2,5};
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        if(n>=8)
        {
            while(n>=8)
            {
                for(int i=0;i<8;i++)
                    cout<<n-a[i]<<' ';
                n-=8;
            }
        }
        if(n==1)
            cout<<"1\n";
        else if(n==2)
            cout<<"2 1\n";
        else if(n==3)
            cout<<"1 2 3\n";
        else if(n==4)
            cout<<"4 3 2 1\n";
        else if(n==5)
            cout<<"5 2 1 4 3\n";
        else if(n==6)
            cout<<"6 5 2 1 4 3\n";
        else if(n==7)
            cout<<"5 2 1 4 3 6 7\n";
    }
}

H

#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<ll>v[2000006];//每个元素的位置
ll cnt=0;
ll s[2000006];//1的位置
void isok()
{
    ll n;
    ll ans=0;
    ll x;
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&x);
        if(x==1)
        {
            v[x].push_back(i);
            s[++cnt]=i;
            ans+=cnt;
        }
        else
        {
            //找这个节点最靠进他的左边界,如果没有那么l=0,这个节点被断开,等后续是否有1加入
            ll l=0;
            //判断是否合法,是否出现过x-1的数 
            if(v[x-1].size())
            {
                l=v[x-1].back();
                //这个x-1被目前的x配对了删去 
                v[x-1].pop_back();
                v[x].push_back(i);
            }
            //只有位置小于等于l的1是可以和目前的元素组成合法序列的
            while(s[cnt]>l) 
                //这个元素1不能和目前的元素组成那对后面的元素也没用了
                //(l,r)不行(l,r+1)也不行
                 cnt--;
            ans+=cnt;
        }
    }
    cout<<ans<<endl;
}
int main()
{
    ll t;
//    cin>>t;
    t=1;
    while(t--)
        isok();
    return 0;
}

后面会慢慢补

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值