A-Shooting Game


题意:
三种球x,y,z分别值1,2,3。给出n种拿球方式和他的id,求价值最大的价值和她对应的id?


题解:知识点:贪心
签到题:就是求每种拿球方式总价值,然后把总价值拍一下序就行了,总价值就是x球个数1+y球个数2+z球个数*3;


代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;

inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆         小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下       大根堆      大到小
map<ll,ll>mp;*/

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;
struct node {
    ll a,b,c;
    ll id;
    ll sum;
}q[maxn];
bool cmp(node a,node b){
    if(a.sum!=b.sum)return a.sum>b.sum;
    else return a.id<b.id;

}
#define read read()
int main(){
     sf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        sf("%lld%lld%lld%lld",&q[i].id,&q[i].a,&q[i].b,&q[i].c);
        q[i].sum=q[i].a+q[i].b*2+q[i].c*3;
    }
    sort(q+1,q+1+n,cmp);
    pf("%lld %lld\n",q[1].id,q[1].sum);
    return 0;
}


B-A Number.....


题意:给你一个整数y,和一个素数p,让你求是否有一个x使得(x*y)mod p = 1;如果这样的x存在,则输出x mod p;否则输出-1。
提示:对于任何整数a和正整数b,mod b是除以b的余数。提醒一下modb是非负的!


题解:知识点:扩展欧几里得
直接化成 yx+ p * b=1 解方程就行了,求x的值,
我们熟知的 是 a
x+b*y=1 这种形式,
所以 其中y就是 a,b就是y ,p就是b,其实就是对应。这样不难想到扩展欧几里得,
就是最后要讨论一下 (y,p)是否互质,如果不互质,而且p为素数,所以最后, 取余之后 结果应该会是0或者y就是不是1,是1就互质了,所以是无解的。


代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;

inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆         小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下       大根堆      大到小
map<ll,ll>mp;*/

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;

ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1,y=0;
        return a;
    }
    ll d=exgcd(b,a%b,y,x);
    y=y-a/b*x;
    return d;    
}

#define read read()
int main(){
     sf("%lld",&t);
    while(t--){
        sf("%lld%lld",&n,&m);
        ll x,y;
        ll gcd=exgcd(n,m,x,y);
        if(gcd==1){
        //cout<<gcd<<endl;
        sum=(x%m+m)%m;
        pf("%lld\n",sum);
        }
        else cout<<-1<<endl;
    }
    return 0;
}


C-City Sup....


题意:n个城市,m条路,1为首都,求n个城市(除了1)到1的最短距离(有路就是两个城市就是1),成本是图片说明 求最小成本?结果取余1e9+7

题解:知识点:最短路
就是用最短路求出来各个点到1的最小距离,然后用快速幂求就行了别忘了取余,还有用long long。


代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e6+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=1e9+7;
const int MOD=10007;

inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆         小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下       大根堆      大到小
map<ll,ll>mp;*/

ll n,m,head[maxn],cnt,dist[maxn],vis[maxn];
struct wmy {
    ll u,v,w,nx;
} a[maxn*4];

ll qpow(ll a,ll b){
    ll sum=1;
    while(b){
        if(b&1) sum=sum*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return sum;
}
void add(ll u,ll v,ll w) {
    a[cnt].u=u;
    a[cnt].v=v;
    a[cnt].w=w;
    a[cnt].nx=head[u];
    head[u]=cnt++;
}
#define read read()
int main(){
    memset(head,-1,sizeof(head));
    cin>>n>>m;
    for(int i=1 ; i<=m ; i++) {
        ll x, y;
        sf("%lld%lld",&x,&y);
        add(x,y,1);
        add(y,x,1);
    }
     memset(dist,inf,sizeof(dist));
    priority_queue<pii,vector<pii>, greater<pii> >q;
    q.push({0,1});
    dist[1]=0;
    while(q.size()) {
        pii fr=q.top();
        q.pop();
        ll dian=fr.second;
        ll dis=fr.first;
        for(int i=head[dian]; ~i; i=a[i].nx) {
            ll e=a[i].v;
            if(dist[e]>dis+a[i].w) {
                dist[e]=dis+a[i].w;
                    q.push({dist[e],e});
            }
        }
    }
    ll ans=0;
    for(int i=2 ; i<=n ; i++)
        ans+=qpow(2,dist[i])%mod,ans%=mod;
    cout<<ans<<endl;
    return 0;
}

D-Moving.....


题意:就是给出你n个数,你的目的是让这n个数都相等你可以进行如下操作:选择一个数+(n-1)并且让其余(n-1)个数-1。当然这个(n-1)个数都是大于0的数。问是否能达到目的?

题解:知识点:优先队列
首先:如果判断这n个数平均数是否为整数,如果不是整数,再怎么变也达不到目的。
如果是整数:首先我们分析一下:我们要达到目的肯定是让小的加,大的减,这样我们那一个优先队列来维护队列中的最小值,因为是1+,多-,所以我们可以不断地测试最小的,如果最小的就是平均数就ok,
如果不是就不行,而且如果最小的小于零,也是不符合题意的。这样一想整体思路是通了。
但是你不能实现 (n-1)个同时-1呀,这样复杂度是过不去的,所以我们要把减的过程,改成O(1)的这样就可以过了,既然是(n-1)个同时减一我们是否可以看成{n个数同时减一,并且第一个数加n}这痒明显是可以的,当然这里第一个数是在变化的,他加上n之后的把+n之后的这个数入队,让队首元素出队,这样才能一个上队首一直维护最小值。然后我们用一个p变量来维护变幻的次数,也就是第一个应该减p测试。这样的话就成功的将复杂度降了下来,变成了O(1).


代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;

inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆         小到大 
/*priority_queue<ll , vector<ll> , less<ll> > mx;//下       大根堆      大到小
map<ll,ll>mp;*/

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;

#define read read()
int main(){
     t=read;
    while(t--){
        n=read;
        while(!mn.empty())mn.pop();
        sum=0;
        for(int i=1;i<=n;i++){
            a[i]=read;
            sum+=a[i];
            mn.push(a[i]);            
        }
        if(sum%n!=0){
            cout<<"No"<<endl;
        }else {
            p=sum/n;
            ll nee=0;
            flag=0;
            for(int i=1;i<=10000;i++){
                if(mn.top()-nee==p){flag=1;break;}
                if(mn.top()-nee<0){flag=0;break;}
                ll temp=mn.top()+n;//因为每一个都要减一所以最后让他 +n
                mn.pop();
                nee++;
                mn.push(temp);
            }
            if(flag) cout<<"Yes"<<endl;
            else cout<<"No"<<endl;
        }


    }
    return 0;
}

F-A Slimple Game


题意:
两个人玩游戏,给出一段字符串,你可以进行的操作有两种:
1,你可以把字符串中一个的'1'变成'0'。
2,你可以把字符串中连续的一段'0',(知道两个)变成一个'1';
给出你n段,你可以同时操作多段,但是一段只能进行一种操作一次。问最后谁获胜。


题解:知识点:博弈论
我们首先通过这两种操作得知最后不能进行是一定是只有一个0,这样就无法进行了

  1. 先看一下'0','1'对结果的影响

    字符串     操作数    加上一个0/操作数  加上两个0/操作数   加上3个0/操作成功数 ......
    1          1         10/3              100/3或者5      1000/3或者5或者7   .....
    11         4        110/4            1100/ 4或者6     11000/ 4或者6或者8  ....
    111        5或者9    ...                ....            ....              ....
    1111       6或者10    ...                ...            ...               ...
    ...
    我们可以得到'1'的数量奇偶决定了操作数的奇偶。而且'0'对最后结果的就行没影响
  2. 我们先看个栗子:
    011和101和110 通过计算演变我们可以知道 这两个其实是等价的,都是可以6次。所以我们得知怎么排的对结果不造成任何影响。
    我们再来看1110 我们可以知道他可以进行9次或者5次

    //x是操作数
    x 字符串
    1 1 1 0
    1 0 1 1 0
    2 0 0 1 0
    3 0 0 0 0
    4 1 0 0
    5 1 1
    6 0 1
    7 0 0
    8 1
    9 0 

    或者

    //x是操作数
    x 字符串
    1110
    1 0110
    2 0010
    3 0000
    4 1
    5 0
  3. 结合上1.2.我们来看当操作数是奇数时:那就是到了(x表示第一个人,y表示第二个人) x完成最后一次 轮不到y所以x赢了。

  4. 在结合上1.2.3.我们看进行多组字符串的

    进行可进行的操作数 每两次的变化  2 4 6 8  ->0 2 4 6 ->0 0 2 4->0 0 0 2->0 0 0 0  第二个人赢了
    因为可以同时进行所以可以同时减   1 3 4-> 从上边推出偶数部分直接减去就可以了
                      最后也就是 1 1 0->第一个人开始使用->0 0 0所以就是第一个人赢         
    以2为一个周期,简单的说就是奇数的话只能是第一个人用 ,第二个人就不能进行操作了,所以第一个人就赢了。

    最后推推 其实也就是很简单了:就是统计每个字符串'1'得个数并判断奇偶,如果有一个是奇数那一定是第一个人赢,否则就是第二个人赢


#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;

inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆         小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下       大根堆      大到小
map<ll,ll>mp;*/

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;

#define read read()
int main(){
     cin>>t;
    while(t--){
        cin>>n;
        ans=0;
        for(int i=1;i<=n;i++){
            p=0;
            cin>>str;
            ll len=str.size();
            for(int i=0;i<len;i++){
                if(str[i]=='1')p++;
            }
            if(p%2==1) ans++;
        }
        if(ans!=0) cout<<"sdzNB"<<endl;
        else cout<<"kgNB"<<endl;

    }
    return 0;
}

G -Gaming with Mia


题意:给出你n个数这些数范围是(-1,0,1)你可以进行2种运算,一种*,另一种+,求结果最大是多少?

题解:知识点:DP
这个题无非就是一段乘积+一段乘积+一段乘积+...

/*
这样无非就是一段段乘积和
两个乘积是//这是不含零的
1*1//这个就用不到
-1*-1
-1*1//这个也用不到
1*-1//这个也用不到

三个乘积是
1*1*1//用不到
-1*-1*1//用不到 可以前两个相乘再加上1
-1*1*-1//这个可以用到
.....
四个乘积  一定是2个-1 和两个1
-1*1*1*-1//可以用
1*-1*1*-1//用不到
-1*1*-1*1//用不到
-1*1*1*-1//
五个乘积我们就可以知道他可以转化成2+3或者1+4或者4+1或者3+2了
后面一样所以只讨论前4种就可以了。
////0的话直接穿***去就行,并不影响我们的分析
*/

代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;

inline ll read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆         小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下       大根堆      大到小
map<ll,ll>mp;*/

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[maxn][2];
string str,s;

#define read read()
int main(){
     t=read;
    while(t--){
        n=read;

        for(int i=1;i<=n;i++) a[i]=read,dp[i][0]=dp[i][1]=0;
        dp[1][0]=a[1];
        dp[1][1]=a[1];
        for(int i=2;i<=n;i++){
            l=a[i]*a[i-1];           
            ans=max(dp[i-2][1]+l,dp[i-2][0]+l);
            dp[i][0]=max(dp[i][0],ans);//两个连乘
            if(i>=3){
            l=a[i]*a[i-1]*a[i-2];//三个连乘
            ans=max(dp[i-3][1]+l,dp[i-3][0]+l);
            dp[i][0]=max(dp[i][0],ans);           
            }
            if(i>=4){
            l=a[i]*a[i-1]*a[i-2]*a[i-3];//四个连乘
            ans=max(dp[i-4][1]+l,dp[i-4][0]+l);
            dp[i][0]=max(dp[i][0],ans);    
            }
            dp[i][1]=max(dp[i][1],dp[i-1][1]+a[i]);
            dp[i][1]=max(dp[i][1],dp[i-1][0]+a[i]);
        }
        cout<<max(dp[n][1],dp[n][0])<<endl;
    }
    return 0;
}