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的值,
我们熟知的 是 ax+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,这样就无法进行了
先看一下'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'对最后结果的就行没影响我们先看个栗子:
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
结合上1.2.我们来看当操作数是奇数时:那就是到了(x表示第一个人,y表示第二个人) x完成最后一次 轮不到y所以x赢了。
在结合上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; }