C 小A的数字(思维,考虑特殊情况)
一、题目要求
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
小A给定一个数字 n,请你帮她找出从低位对齐后任意一位均与 n对应数位不同的最小正整数。
对于本题题面描述中的从低位对齐后任意一位均与 n 对应数位不同,你需要保证你所输出的答案的位数小于 n 的位数时,即使在添加前导零至与 n 的位数相同后,也不应有任意一位的数字两两相同。
输入描述:
多组测试。
第一行一个正整数 T (1≤T≤10^3)表示测试数据组数。
对于每组测试数据,一行一个不含前导零的整数 n(2≤n≤10^9),表示所给的数字。
输出描述:
对于每组测试,输出一行一个正整数表示答案。
示例1
输入
3 2 10 101
输出
1 1 10
二、思路
1.主要特殊考虑全1的情况,例如11,111,他们的最小整数为2
2.考虑该串数字全是在2~9之间,所以最大可以为1
3.例如121 变为10 122231 000000 然后如果最后一位原来是1,直接将倒数第1位变为2
1112 0000 -> 0001
4.总结:先将一个字符串里面,非0的数变为0,0变为1
a.先去考虑全1的情况
b.如果变完为0,则看原来的最后一位,若原来最后一位是‘1’,则最小正整数为2,若是其他情况就变为1
c.除了以上情况,其他就按原来的变化后的数字进行输出,例如1101 0010-> 10
三、代码
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
#define int long long
using namespace std;
typedef pair<int,int>PII;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
int n,m;
void solve()
{
cin>>n;
int i,j;
while(n--)
{
int x;
cin>>x;
if(x<=99)
{
if(x==11)
cout<<2<<endl;
else
cout<<1<<endl;
}
else
{
string s=to_string(x);
int len=s.size();
char p=s[len-1];
int cnt=0;
for(i=len-1; i>=0; i--)
{
if(s[i]=='1')
cnt++;
if(s[i]!='0')
s[i]='0';
else if(s[i]=='0')
s[i]='1';
}
int h=stoi(s);
if(cnt==len)
{
cout<<"2"<<endl;
}
else
{
if(h==0)
{
if(p=='1')
h=2;
else
h=1;
}
cout<<h<<endl;
}
}
}
}
signed main()
{
int t=1;
while(t--)
{
//快输
solve();
}
return 0;
}
D 小A的线段(easy version)(二进制+差分)
一、题目要求
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
在一个标有 1−n的数轴上给定 m条线段,第 i 个线段的左右端点分别为 sti , edi,求有多少种线段的选择方案可以使得数轴上的每个整数点至少被覆盖两次。
定义两种选择方案不同当且仅当至少有一个线段在两种方案中的状态(选/不选)不同。
由于方案数可能很多,所以你需要输出满足条件的方案数对 998244353取模的结果。
输入描述:
第一行两个正整数 n(2≤n≤10^5)和 m(1≤m≤10),分别表示数轴长度和线段个数。 接下来 m行,每行两个正整数,其中第 i 行的两个正整数 sti 和 edi(1≤sti<edi≤n) 分别表示第 i条线段的起点和终点。
输出描述:
输出满足条件的方案数对 998244353 取模的结果。
示例1
输入
5 4 4 5 1 5 3 5 1 4
输出
3
二、 思路
1.利用二进制,0表示不选,1表示选,时间复杂度一般为o(2^m*m),当m为[1,16],时间复杂度大约就是1e6左右,本题数据范围,m属于[1,10]
2.(i>>k)&1 判断第k位是否为1 (1<<m) 2^m
3.利用差分操作,对端点出进行处理。
三、代码
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
#define int long long
using namespace std;
typedef pair<int,int>PII;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
int n,m;
int l[N],r[N],f[N];
void solve()
{
cin>>n>>m;
int i,j;
for(i=1;i<=m;i++)
{
cin>>l[i]>>r[i];
}
int ans=0;
for(i=0;i<(1<<m);i++)
{
for(j=1;j<=n;j++)
f[j]=0;
for(j=0;j<m;j++)//枚举
{
if((i>>j)&1)//判断第j位是否为1,为1
{
// cout<<i<<' '<<j<<endl;
//选这条线段,进行差分操作
f[l[j+1]]++;
f[r[j+1]+1]--;
}
}
for(j=1;j<=n;j++)
{
f[j]+=f[j-1];
if(f[j]<2)
break;
}
if(j>n)//从1~n 遍历过
{
//cout<<"j="<<j<<endl;
ans++;
}
}
cout<<ans<<endl;
}
signed main()
{
int t=1;
while(t--)
{
//快输
solve();
}
return 0;
}
E 小A的任务(思维+优先队列)
一、题目要求
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
小A现在需要完成有序的 A 类任务和 B 类任务各 n 个,初始时只有第 1 个 A 类任务可以进行。进行第 i 个 A类任务需在完成第 i − 1 个 A 类任务之后,进行第 i个 B 类任务需要在完成第 i 个 A 类任务之后。且在同一时刻只能进行 A类和 B类中的一类任务,同一类的任务只能同时进行一个,任何一个任务都至多完成一次。
总共有 q 次询问,每次询问你需要回答完成 k 个 B 类任务至少需要多长时间。
输入描述:
第一行两个整数 n (1≤n≤10^5)和 q (1≤q≤100)分别表示任务个数与询问次数。 第二行 n 个整数,其中第 i个数字 ai (1≤ai≤10^9)表示完成第 i 个 A 类任务所需要的时间。 第三行 n个整数,其中第 i个数字 bi (1≤bi≤10^9)表示完成第 i 个 B类任务所需要的时间。 接下来 q行,每行一个整数 k (1≤k≤n),表示询问。
输出描述:
对于每次询问,输出一行一个整数,表示询问结果。
示例1
输入
4 3 1 2 3 4 4 1 2 3 1 2 3
输出
4 8 13
示例2
输入
5 2 19 1 20 2 17 12 20 17 4 2 3 5
输出
75 114
备注:
对于样例一的第一个询问,需要先完成前 2 个 A 类任务,再完成第 2 个 B 类任务。
二、思路
1.利用优先队列,priority_queue<int>q 默认大根堆,将A任务直接用前缀和
2.任务顺序:只有k个A任务完成后,才能从1~k个里面选择B任务;若cnt>k后,我们可以选择,完成前cnt个任务,再从1~cnt里面选择k个B任务而从这里面选择,自然从1~cnt里面选出来前k个最小的任务+a[cnt]最小则为最优解。
三、代码
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
int n,t;
int a[N],b[N];
void solve()
{
cin>>n>>t;
int i,j,k;
for(i=1;i<=n;i++)
{
cin>>a[i];
a[i]+=a[i-1];
}
for(i=1;i<=n;i++)
cin>>b[i];
while(t--)
{
cin>>k;
priority_queue<int>q;//默认大根堆,从大到小排
int sx=0,mx=1e18,cnt=0;
for(i=1;i<=n;i++)
{
if(i<=k)//先入队 前k个
{
q.push(b[i]);
sx+=b[i];
cnt++;
}
else//当它>k之后
{
int tt=q.top();
if(b[i]<tt)//如果当前这个数,比已经入队的q队列里面的最大值还小
{
q.pop();//将合适的b[i]入队后,队列里面有k个数
q.push(b[i]);//将其入队
sx=sx-tt+b[i];//更新所有的时间
}
}
if(cnt==k)
mx=min(mx,sx+a[i]);
}
cout<<mx<<endl;
}
}
signed main()
{
int t=1;
while(t--)
{
//快输
solve();
}
return 0;
}