目录
A. Round Down the Price
B. Polycarp Writes a String from Memory
C. Train and Queries
D. Not a Cheap String
E. Split Into Two Sets
F. Equate Multisets
G1. Passable Paths (easy version)
题意:给一个数,该数减去需要求的一个数后,会是最大的10的某次方数。
输入:
7 1 2 178 20 999999999 9000 987654321
输出:
0 1 78 10 899999999 8000 887654321
思路:
找出和该数同位的10的幂数,减去即可
代码:
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define M 1000005
int T,n,s;
signed main(){
cin>>n;
fo(1,n){
cin>>s;
int ans=1;
int ss=s;
while(ss) ans*=10,ss/=10;
cout<
题意:一个字符串只能从前往后取,每次最多取三种不一样的字符,求最少多少次取完
输入:
6 lollipops stringology abracadabra codeforces test f
输出:
2 4 3 4 1 1
思路:
暴力模拟,用数组存是否已经取过,超过4个的点就是下次取的第一个点,最后的没取到3种的也算1次
代码:
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define mem(a,b) memset(a,b,sizeof(a))
#define M 1000005
int T,n;
int vis[205];
string s;
signed main(){
cin>>T;
while(T--){
cin>>s;
mem(vis,0); //清空
int l=(int)s.size();
int sum=0,s1=0;
fo(0,l-1){
if(vis[s[i]]==0) sum++;
if(sum==4){ //超了的话,该点就算下次取的第一点
s1++;
mem(vis,0); //清空
sum=1;
}
vis[s[i]]=1;
}
cout<
题意:给一个数组,前面的点能到后面的任意一点,但是后面的不能到前面,且不能到路的中间(即只有起点到终点)。问两点能不能到
输入:
3 6 3 3 7 1 5 1 4 3 5 1 7 3 10 3 3 1 2 1 2 1 1 2 4 5 7 5 2 1 1 1 2 4 4 1 3 1 4 2 1 4 1 1 2
输出:
YES NO NO YES YES NO NO YES YES NO YES
思路:
一个点为起点的话,最记最前面的点的位置即可,因为后面的该点能到,前面的也一定能到。
终点只记末尾位置即可,要是起点位置比终点大,或者没有该点出现直接输出NO
代码:
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define M 1000005
int T,n,m,l,r;
int a[M];
mapmpx,mpy;
signed main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
mpx.clear();
mpy.clear();
fo(1,n) cin>>a[i],mpx[a[i]]=i; //mpx为点的终点位置
for(int i=n;i>=1;i--) mpy[a[i]]=i; //起点
while(m--){
cin>>l>>r;
if(mpy[l]==0||mpx[r]==0||mpy[l]>mpx[r]) cout<<"NO"<
题意:一些字符串,s[i]的价值是s[i]-'a'+1,找出长度最长的子序列价值和<=k。
输入:
5 abca 2 abca 6 codeforces 1 codeforces 10 codeforces 100
输出:
aa abc cdc codeforces
思路:
贪心选即可,从'a'开始选,选完后根据标记找出这个子序列
代码:
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define mem(a,b) memset(a,b,sizeof(a))
#define M 1000005
int T,n,k;
int vis[205],v[205];
char s[M];
signed main(){
scanf("%d",&T);
while(T--){
mem(vis,0);
mem(v,0);
scanf("%s",s);
n=strlen(s);
scanf("%d",&k);
fo(0,n-1) vis[s[i]]++;
int j='a';
while(k>=1&&j<='z'){
if(vis[j]&&k-(j-'a'+1)>=0) vis[j]--,v[j]++,k-=(j-'a'+1); //v[j]表示字符j已选的数量
else j++;
}
string tmp;
fo(0,n-1){
if(v[s[i]]){ //根据已选数量选择字符
v[s[i]]--;
tmp+=s[i];
}
}
cout<
题意:给n个二元组,问能不能分成两份,每份中没有重复的数字。
输入:
6 4 1 2 4 3 2 1 3 4 6 1 2 4 5 1 3 4 6 2 3 5 6 2 1 1 2 2 2 1 2 2 1 8 2 1 1 2 4 3 4 3 5 6 5 7 8 6 7 8 8 1 2 2 1 4 3 5 3 5 4 6 7 8 6 7 8
输出:
YES NO NO YES YES NO
思路:
首先里面的数字是1-n的,那么每份的数字一定会是1-n,也就是每份二元组的数量一定是n/2的。
所以每个数字出现次数就是2次,每个点能到达的也就是两个点(类似于双边的图)。
从一个点开始走,路是唯一的,直到遇到已经走过的点,而该点一定是出发点,这样就形成一个闭环,这个闭环点的数量为奇数的话,答案就是NO。
比如
3
1 1
2 3
2 3
从1出发在1处闭环,数量为奇数答案直接为NO;从2出发到3,再到2为闭环,数量为2不影响答案。
代码:
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define M 1000005
int T,n,x,y;
int vis[M];
vectorv[M];
signed main(){
scanf("%d",&T);
for(int k=1;k<=T;k++){
int flag=0;
scanf("%d",&n);
fo(1,n) v[i].clear();
fo(1,n){
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
fo(1,n){
if(v[i].size()!=2){
flag=1;
break;
}
int id=i,sum=0;
while(vis[id]!=k){ //id表示从i点出发的路径点
vis[id]=k; //标记id点走过
sum++;
if(vis[v[id][0]]!=k) id=v[id][0]; //如果一个点没有过就走
else id=v[id][1];
}
if(sum%2) flag=1;
}
printf("%s\n",flag?"NO":"YES");
}
return 0;
}
题意:给两个数组,问b数组中的数组随便除以2向下取整,或者随便乘以2,能不能为a数组
输入:
5 4 2 4 5 24 1 4 6 11 3 1 4 17 4 5 31 5 4 7 10 13 14 2 14 14 26 42 5 2 2 4 4 4 28 46 62 71 98 6 1 2 10 16 64 80 20 43 60 74 85 99
输出:
YES NO YES YES YES
思路:
a数组中所有偶数不停/2变为奇数,不会影响答案,比如a中的10,b中有一个数能变为10,就一定可以变为5
b数组同理,都不停/2变为奇数
那么此时的b数组只能做/2一种了,因为a数组都是奇数,你乘2是不是也没有用
map存一下a数组中的奇数,b数组不停的/2,匹配即可
代码:
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define int long long
#define M 1000005
int T,n,f=0;
int a[M],b[M];
mapmp;
void solve(int &x){ //除2
while(x%2==0) x/=2;
}
string fin(){
fo(1,n){
while(b[i]&&mp[b[i]]==0) b[i]/=2;
if(!b[i]) return "NO";
mp[b[i]]--;
}
return "YES";
}
signed main(){
scanf("%lld",&T);
while(T--){
mp.clear();
scanf("%lld",&n);
fo(1,n) cin>>a[i],solve(a[i]),mp[a[i]]++;
fo(1,n) cin>>b[i],solve(b[i]);
cout<
题意:给一个树,问如若干个点是否在树上是一个链,也就是有没有一条不回头的路穿过所有给定的点
输入:
5 1 2 2 3 2 4 4 5 5 3 3 2 5 5 1 2 3 4 5 2 1 4 3 1 3 5 3 1 5 4
输出:
YES NO YES NO YES
思路:这个是easy版本的,询问只有5次以下,我的思路是预处理高度,高度最大的点一定是该链的起点,每次需要从该点dfs遍历整个树,将出现过的点+1,问有没有加到点的数量的。
但是这个方法对hard的下题就不行了
代码:
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define int long long
#define M 200005
int T,n,m,x,y,l,flag;
int q[M];
vectorv[M];
int h[M];
mapmp;
int cmp(int x,int y){
return h[x]>h[y];
}
void dfs(int d,int pre)
{
h[d]=h[pre]+1; //处理高度
int l=v[d].size();
fo(0,l-1){
int now=v[d][i];
if(pre!=now){
dfs(now,d);
}
}
}
void qdfs(int d,int pre,int s)
{
if(s==l){ //如果等于询问点的数量,答案是YES
flag=1;
return;
}
int l=v[d].size();
fo(0,l-1){
int now=v[d][i];
if(pre!=now){
int res=mp[now];
qdfs(now,d,s+res); //s+是否是询问的点
}
}
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cin>>n;
fo(1,n-1){
cin>>x>>y;
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1,0);
cin>>m;
while(m--){
flag=0;
mp.clear();
cin>>l;
fo(1,l) cin>>q[i],mp[q[i]]=1;
sort(q+1,q+l+1,cmp);
qdfs(q[1],0,1); //从高度最大的点开始遍历
cout<<(flag?"YES":"NO")<