biubiu-biu r a t i n g + = 162 rating+=162 rating+=162 1500->1662
题意
给你两个数 n n n, m m m,每次可以把 n n n乘 2 2 2或者乘 3 3 3,问多少次操作之后 n n n可以变成 m m m。不能输出 − 1 -1 −1。
做法
首先判断是否整除,之后用商不断除以 2 2 2/除以 3 3 3最后判结果是否为 1 1 1就可以。
代码
#include
int main()
{
int n,m;
scanf("%d%d",&n,&m);
if(m%n!=0||m<n)
{
printf("-1");
return 0;
}
int tmp=m/n;
int cnt=0;
while(tmp%2==0)
{
tmp/=2;
cnt++;
}
while(tmp%3==0)
{
tmp/=3;
cnt++;
}
if(tmp!=1) printf("-1\n");
else printf("%d\n",cnt);
return 0;
}
题意
给你一个长度为 n n n的 01 01 01串构成的环,问环上最长的连续的 1 1 1是多长,
做法
按题意模拟即可。
代码
#include
#include
#include
using namespace std;
const int maxn = 2e5+5;
int a[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int ans=0;
for(int i=1;i<=n;i++)
{
if(a[i]==1)
{
int cnt=0;
while(i<=n&&a[i]==1)
{
i++;
cnt++;
}
ans=max(ans,cnt);
i--;
}
}
int tmp=0;
for(int i=1;i<=n;i++)
{
if(a[i]==1) tmp++;
else break;
}
for(int i=n;i>=1;i--)
{
if(a[i]==1) tmp++;
else break;
}
ans=max(ans,tmp);
printf("%d\n",ans);
return 0;
}
题意
给你一个长度为 n n n的数组差分后的数组(差分数组长度为 n − 1 n-1 n−1)。
问原数组是否是一个 1 − n 1-n 1−n的排列。
做法
首先我们可以知道如果固定数组中的第一个数,就能还原数组,而且如果原数组是 [ 1 , n ] [1,n] [1,n]排列,还原后的数组一定是 [ k , k + n − 1 ] [k ,k+n-1] [k,k+n−1]的排列,所以只要判断还原后的数组是否满足情况即可。注意下标不要越界。
代码
#include
#include
#include
using namespace std;
const int maxn = 2e5+5;
const int INF = 0x3f3f3f3f;
int a[maxn];
int vis[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n-1;i++) scanf("%d",&a[i]);
int minn=INF,maxx=-INF;
a[0]=0;
for(int i=1;i<=n-1;i++)
{
a[i]=a[i-1]+a[i];
minn=min(minn,a[i]);
maxx=max(maxx,a[i]);
}
minn=min(minn,0);
maxx=max(maxx,0);
if(maxx-minn+1==n)
{
for(int i=0;i<=n-1;i++) a[i]=a[i]+(1-minn);
for(int i=0;i<=n-1;i++)
{
if(vis[a[i]])
{
printf("-1\n");
return 0;
}
vis[a[i]]=1;
}
for(int i=0;i<=n-1;i++) printf("%d ",a[i]);
}
else printf("-1\n");
return 0;
}
题意
给你两个长度为 n n n的字符串,字符集为小写字母和?
。两个字符匹配的条件是要么两个字符相等,要么其中一个字符为?
。问两个字符串最多有多少对字符匹配。
做法
首先如果两个字符相等而且是小写字母肯定直接匹配,不浪费?
。
之后两边分别用?
去匹配剩下的小写字母,最后如果两端?
均有剩余,再用两个?
进行匹配。
代码
#include
#include
#include
#include
using namespace std;
typedef pair <int, int> pii;
const int maxn =2e5+5;
#define Se second
#define Fi first
#define pb push_back
int sum[2][27];
char str1[maxn],str2[maxn];
vector<int> tt[2][27];
vector<pii> ansv;
int main()
{
//ios::sync_with_stdio(false);
//freopen("a.txt","r",stdin);
//freopen("b.txt","w",stdout);
int n;
scanf("%d",&n);
scanf("%s",str1);
scanf("%s",str2);
for(int i=0;i<n;i++)
{
if(str1[i]=='?')
{
tt[0][26].push_back(i+1);
sum[0][26]++;
}
else
{
tt[0][str1[i]-'a'].pb(i+1);
sum[0][str1[i]-'a']++;
}
}
for(int i=0;i<n;i++)
{
if(str2[i]=='?')
{
tt[1][26].push_back(i+1);
sum[1][26]++;
}
else
{
tt[1][str2[i]-'a'].pb(i+1);
sum[1][str2[i]-'a']++;
}
}
int ans=0;
int cnt1=0,cnt2=0;
for(int i=0;i<26;i++)
{
ans+=min(sum[0][i],sum[1][i]);
int tmp=min(sum[0][i],sum[1][i]);
int ty=min(tt[0][i].size(),tt[1][i].size());
for(int j=tt[0][i].size()-1,k=tt[1][i].size()-1;j>=0&&k>=0;j--,k--)
{
ansv.push_back(pii(tt[0][i][j],tt[1][i][k]));
tt[0][i].pop_back();
tt[1][i].pop_back();
}
}
for(int i=0;i<26;i++)
{
if(tt[0][i].size()>0)
{
int tq=tt[0][i].size()-1;
while(sum[1][26]>0&&tq>=0)
{
sum[1][26]--;
ans++;
ansv.push_back(pii(tt[0][i][tq],tt[1][26][sum[1][26]]));
tq--;
}
}
if(tt[1][i].size()>0)
{
int tq=tt[1][i].size()-1;
while(sum[0][26]>0&&tq>=0)
{
sum[0][26]--;
ans++;
ansv.push_back(pii(tt[0][26][sum[0][26]],tt[1][i][tq]));
tq--;
}
}
}
while(sum[0][26]>0&&sum[1][26]>0)
{
sum[0][26]--;
sum[1][26]--;
ans++;
ansv.push_back(pii(tt[0][26][sum[0][26]],tt[1][26][sum[1][26]]));
}
printf("%d\n",ans);
for(int i=0;i<ans;i++) printf("%d %d\n",ansv[i].Fi,ansv[i].Se);
return 0;
}
题意
有一个怪兽,初始血量为 H H H,他的血量变化情况是一个长度为 n n n轮的周期。问怪兽会在第几轮死去。
1 ≤ H ≤ 1 0 12 1 \leq H \leq 10^{12} 1≤H≤1012
1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1≤n≤2×105
做法
首先如果怪兽血量在一个周期内不曾小于等于 0 0 0而且每个周期之后怪兽血量增加,直接输出 − 1 -1 −1。
之后要知道,怪兽在某个完整的周期之前到达x血量,怪兽就撑不过这轮。
这个 x x x的求法就是遍历一遍周期,找到某个时刻怪兽血量消耗最多。
之后就假设怪兽初始血量为 H − x H-x H−x。看怪兽能撑过几个完整的轮,设这里轮数为 k k k,每轮怪兽血量减少 s u m sum sum,则要满足
s u m × k + x ≥ H sum\times k+x\ge H sum×k+x≥H
k ≥ H − x s u m k\ge \frac{H-x}{sum} k≥sumH−x
所以不等式右面要上取整得到 k k k,之后再 O ( n ) O(n) O(n)的进行一个周期看怪兽在第几轮死即可。
代码
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
int a[maxn];
int n;
ll H;
ll sum;
int check(ll mid)
{
ll tt=H;
tt+=(mid-1)*sum;
if(tt<=0) return 0;
for(int i=1;i<=n;i++)
{
tt+=a[i];
if(tt<=0) return i;
}
return -1;
}
int main()
{
scanf("%lld%d",&H,&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sum=0;
int flag=0;
ll tmp=H;
ll minn=LL_INF;
int pos;
for(int i=1;i<=n;i++)
{
sum+=a[i];
tmp+=a[i];
if(sum<minn)
{
minn=sum;
pos=i;
}
if(tmp<=0)
{
flag=i;
break;
}
}
if(flag!=0)
{
printf("%d\n",flag);
return 0;
}
if(sum>=0)
{
printf("-1");
return 0;
}
minn=-minn;
sum=-sum;
ll ans=(H-minn)/sum+((H-minn)%sum!=0);
H=H-ans*sum;
if(H==0)
{
printf("%lld\n",ans*n);
return 0;
}
for(int i=1;i<=n;i++)
{
H+=a[i];
if(H<=0)
{
printf("%lld\n",ans*n+i);
return 0;
}
}
return 0;
}
题意
给你一个长度为n的数组,找出尽量多的不相交的区间并且他们的区间和相等。
1 ≤ n ≤ 1500 1 \leq n \leq 1500 1≤n≤1500
做法
由于 n = 1500 n=1500 n=1500,区间和只有 1500 × 1500 1500 \times 1500 1500×1500 种,所以我们这些区间和作为最终的答案,对于每种区间和可以得到很个区间,对于每种区间和的问题就转化为给你n个区间找出最多的不相交区间的问题,这个问题按照r排序之后贪心的从左到右选即可,之后对每种区间和的答案取 m a x max max,这道题就做完了。
代码
#include
#include
#include
#include
#include
#include
using namespace std;
typedef pair <int, int> pii;
const int maxn = 1e6+5;
#define pb push_back
#define Se second
#define Fi first
int a[maxn];
vector<pii> anss;
vector<pii>tmp;
map<int,int> r;
unordered_map<int,vector<pii>> mp;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) a[i]=a[i-1]+a[i];
int ans=1;
anss.push_back(pii(1,1));
vector<int> rr;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
int tmp=a[i]-a[j-1];
if(r.find(tmp)==r.end()||r[tmp]<j)
{
mp[tmp].pb(pii(j,i));
r[tmp]=i;
}
}
}
for(unordered_map<int,vector<pii> >::iterator it=mp.begin();it!=mp.end();++it)
{
if((*it).Se.size()>ans)
{
ans=(*it).Se.size();
anss=(*it).Se;
}
}
printf("%d\n",ans);
for(int i=0;i<ans;i++) printf("%d %d\n",anss[i].Fi,anss[i].Se);
return 0;
}
题意
给你一棵 n n n个结点的树,现在要对每条边染色,如果一个节点所连接的边的颜色中有相同的,则这个点是坏点,现在问如果要使坏点的个数不超过 k k k,问最少要用多少种颜色去染边。
做法
首先由于这是一颗树,也就是每两个点只会被一条边影响,所以可以认为每个点染色是独立的。因为对于每条边至少染一种颜色,所以这条边如何染色不影响另一个点,之后我们贪心的选择度数最大的 k k k个点去放弃这些点,然后从任意一点开始 d f s dfs dfs染色即可。对于不放弃的点,他与所有子节点和父节点的边颜色均不相同。对于已放弃的点,全都染同一个色即可。最后统计最多用了几种颜色。
代码
#include
#include
#include
#include
using namespace std;
typedef pair <int, int> pii;
const int maxn = 2e5+5;
#define Fi first
#define Se second
#define pb push_back
struct data
{
int pos;
int ind;
}x[maxn];
vector<pii>G[maxn];
bool cmp(const data &a,const data &b)
{
if(a.ind==b.ind) return a.pos<b.pos;
return a.ind>b.ind;
}
int vis[maxn];
int ans[maxn];
void dfs(int rt,int fa,int col)
{
int tmp=0;
for(int i=0;i<G[rt].size();i++)
{
int to=G[rt][i].Fi;
int id=G[rt][i].Se;
if(to==fa) continue;
if(vis[rt]==1)
{
ans[id]=1;
dfs(to,rt,1);
}
else
{
if(++tmp==col) tmp++;
ans[id]=tmp;
dfs(to,rt,tmp);
}
}
}
int main()
{
int n,k,u,v;
scanf("%d%d",&n,&k);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
G[u].pb(pii(v,i));
G[v].pb(pii(u,i));
x[u].ind++;
x[v].ind++;
}
for(int i=1;i<=n;i++) x[i].pos=i;
sort(x+1,x+1+n,cmp);
for(int i=1;i<=k;i++) vis[x[i].pos]=1;
dfs(1,-1,-1);
int maxx=0;
for(int i=1;i<=n-1;i++) maxx=max(maxx,ans[i]);
printf("%d\n",maxx);
for(int i=1;i<=n-1;i++) printf("%d ",ans[i]);
return 0;
}