A - Collecting Coins
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
int main()
{
ll q;cin>>q;
while(q--){
ll a,b,c,n;
cin>>a>>b>>c>>n;
ll zy=max(a,max(b,c));
ll libm=zy-a+zy-b+zy-c;
n-=libm;
if(n<0){
cout<<"NO"<<endl;
continue;
}
if(n%3==0){
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
}
}
B - Collecting Packages
题意:有个机器人,只能向上走或者向右走,要从(0,0)经过所有的点(xi,yi),求是否可行,若可行则输出字典序最小的方案。
题解:字典序最小就是说先往右走再往上走。直接把所有点按x排序,要求每个点与(0,0)包围的矩形包含此前的所有点,只需要比前面的点都高就行了。由数学归纳法可知只需要比前一个点高就行了
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
struct node{
ll x,y;
};
int cmp(node a,node b){
if(a.x==b.x){
return a.y<b.y;
}
return a.x<b.x;
}
int main()
{
ll q;cin>>q;
while(q--){
node libm[1005];
ll n;cin>>n;
ll maxx=0,maxy=0;
for(int i=1;i<=n;i++){
cin>>libm[i].x>>libm[i].y;
}
int flag=0;
sort(libm+1,libm+n+1,cmp);
for(int i=1;i<=n;i++){
maxx=max(maxx,libm[i].x);
maxy=max(maxy,libm[i].y);
if(libm[i].x<maxx||libm[i].y<maxy){
flag=1;
break;
}
}
if(flag) cout<<"NO"<<endl;
else {
libm[0].x=0;libm[0].y=0;
cout<<"YES"<<endl;
for(int i=1;i<=n;i++){
ll xx=libm[i].x-libm[i-1].x;
ll yy=libm[i].y-libm[i-1].y;
for(int i=1;i<=xx;i++){
cout<<"R";
}
for(int i=1;i<=yy;i++){
cout<<"U";
}
}
cout<<endl;
}
}
}
C - Product of Three Numbers
题意:给一个数n,满足n>=2,要求将n分解成互异的三个数a,b,c,使得abc==n,且a,b,c>=2。给出一种分解的方案,或者说明其不存在。
题解:有两种写法,一种是纯暴力,但是注意记录个数(我就在这里爆炸了);还有一种是唯一分解定理的解法
先上暴力:
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int maxn=1e5+5;
bool vis[maxn];
int prime[maxn],cnt=0;
int main()
{
int q;cin>>q;
while(q--){
ll n;cin>>n;
ll a[5];
ll cnt=0;
int flag=0;
for(int i=2;i<=maxn;i++){
if(n%i==0){
n/=i;
cnt++;
a[cnt]=i;
}
if(i>=n){
flag=1;
break;
}
if(cnt==2) break;
}
if(cnt==0) flag=1;
if(cnt==1&&n>maxn) flag=1;
if(flag) cout<<"NO"<<endl;
else{
cout<<"YES"<<endl;
cout<<a[1]<<" "<<a[2]<<" "<<n<<endl;
}
}
}
这个是唯一分解定理的解法:
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int maxn=1e5+5;
int p[maxn];
int main()
{
int q;cin>>q;
while(q--){
ll n;cin>>n;
int cnt=0;
for(int i=2;i*i<=n;i++){
while(n%i==0){
p[++cnt]=i;
n/=i;
}
}
if(n!=1) p[++cnt]=n;
int a=1,b=1,c=1;
for(int i=1;i<=cnt;i++){
if(a==1) a*=p[i];
else if(b==1||a==b) b*=p[i];
else c*=p[i];
}
if(a==1||b==1||c==1||a==b||b==c||a==c)printf("NO\n");
else printf("YES\n%d %d %d\n",a,b,c);
}
}
D - MEX maximizing
题意:有q次操作和一个固定的正整数x,每次操作会往序列中加入一个数字y,你可以在任何时候对序列中的某个y进行任意多次加减x操作(但不能使他们变成负数),求使得整个序列的MEX最大的方案时的MEX的值。
题解:显然模x余数相同的都是同一种等价的东西,可以维护模x值不同结果的cnt。那么MEX操作就相当于询问整个cnt序列中的最小值(这个最小值是一层一层循环叠在下面把MEX垫高),然后再求序列中等于这个最小值的最左边的元素,这个显然可以用线段树来维护(甚至可以支持修改删除)。
但是最简单的操作还是在cnt里面数了之后不断尝试越过MEX即可。
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define mem(a) memset(a,0,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int maxn=4e5+5;
const int INF=0x3f3f3f3f;
ll ans,cnt[maxn];
int main()
{
ll q,x;cin>>q>>x;
while(q--){
ll n;cin>>n;
cnt[n%x]++;
while(cnt[ans%x]){
cnt[ans%x]--;
ans++;
}
cout<<ans<<endl;
}
}