题意:
给定一个非负整数n,求是否存在三个整数使得
(a⊕b)+(b⊕c)+(a⊕c)=n,并输出a,b,c
题解:
先讨论a,b,c转换为二进制后的最后一位
所以n只能是偶数
然后假设a=b,那么a⊕b=0,然后a⊕c=n/2,再假设a=b=0,那么c=n/2
#include
using namespace std;
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
if (n%2==1) cout<<-1<<endl;
else cout<<"0 0 "<<n/2<<endl;
}
return 0;
}
题意:
给定两个偶数 n , m ,求 n × m的二进制矩阵,满足对于矩阵内任意位置 ( i , j ),在上下左右的四个方向上均有恰好两个与该元素不同的元素。
题解:
从样例找规律
两行的时候:
10011001
01100110
四行的时候
10011001
01100110
01100110
10011001
八行的就不写了,太长了
不难看出答案是由下面这个拼接起来的
1001
0110
0110
1001
所以只需提前将这个矩阵保存起来,然后就将它按大小循环输出即可
#include
using namespace std;
int a[4][4]={{1,0,0,1},
{0,1,1,0},
{0,1,1,0},
{1,0,0,1}};
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
cout << a[i%4][j%4] << " ";
cout<<endl;
}
}
return 0;
}
题意:
给定一个0到n-1的排列a,问有多少种0到n-1的排列b,满足排列a跟排列b相似
两个排列相似指两个排列的任意区间 [ l , r ] 上的子区间的MEX 值相同。 MEX值是指数组未出现的最小的非负整数。
题解:
我们考虑,如果一个区间[L,R]其mex([L,R])==x则说明0到x-1的数都在这个区间里出现过了。
所以我们需要从0到n-1枚举i,并且记录0到i-1出现的数的最左和最右的端点[L,R]
那么,如果枚举到的i的位置a[i]落在了区间[L,R]中,那么剩下的R-L+1-i是可以随便放的。
#include
using namespace std;
const int N=1e5+5;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
typedef long long ll;
ll a[N];
int main()
{
int T;
cin>>T;
while(T--)
{
ll n;
cin>>n;
for (ll i=1;i<=n;i++)
{
ll x;
cin>>x;
a[x]=i;
}
ll l=INF,r=-1;
ll res=1;
for (ll i=0;i<n;i++)
{
if (a[i]<=r && a[i]>=l)
{
res=res*(r-l+1-i)%mod;
}
l=min(l,a[i]);
r=max(r,a[i]);
}
cout<<res<<endl;
}
return 0;
}
题意:
给定一个长度为n的数组a,可以对数组进行操作,每次操作可以选择相邻的两个数,当且仅当两个数相同时可以删掉这两个数。求进行若干次操作后,剩下的数组长度最长是多少?
题解:
dp表示:
f[i]表示以第i位数结尾的剩下的长度中最长是多少。
当f[i]==f[j]时,需要解决的是中间的数能否删掉
如果能删掉,这个区间的长度必须是偶数,如果是奇数的话,一定会剩下一个的。并且我们有个结论,区间内的众数的次数不能超过总长度的一半。符合条件就能删掉。
第i个数的前面所有数都删掉或者n个数全部删掉也要做特殊处理。因为a[i]的范围是在1到n,所以只需设a[0]和a[n+1]为0即可。
#include
using namespace std;
const int N=1e5+5;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
typedef long long ll;
ll a[N],f[N],b[N];
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i];
f[i]=0;
}
a[0]=0;
a[n+1]=0;
ll res=0;
for (int i=1;i<=n+1;i++)
{
ll v=-INF;
ll cnt=0;
for (int j=0;j<=n;j++) b[j]=0;
for (int j=i-1;j>=0;j--)
{
if (j+1
题意:
给定一个n*m的矩阵,a[i][j]=(i-1)*m+j,每次只能往右或者下移动,问从左上角到右下角,经过的位置的和的最小值
题解:
走第一行,最后一列
#include
using namespace std;
typedef long long ll;
int main()
{
int T;
cin>>T;
while(T--)
{
ll n,m;
cin>>n>>m;
ll res=0;
for (ll i=1;i<=m;i++) res+=i;
for (ll i=2;i<=n;i++) res+=i*m;
cout<<res<<endl;
}
return 0;
}
题意:
给定一个长度为 n 的长整数, 求出一个长度为 n (没有前导零), 且和它相加为回文串的整数.
题解:
#include
using namespace std;
typedef long long ll;
int n;
string sub1(string s,int x)
{
string res="";
int t=0;
for (int i=n-1;i>=0;i--)
{
int a=x-t,b=s[i]-'0';
t=0;
if (a<b)
{
t=1;
a+=10;
}
a-=b;
res=char(a+'0')+res;
}
return res;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n;
string s;
cin>>s;
if (s[0]=='9') cout<<sub1(s,1)<<endl;
else cout<<sub1(s,9)<<endl;
}
return 0;
}
题意:
给定一个数组a,有三种操作:
求使所有数变为 0 的最小操作数.
题解:
看到区间的加和减,用差分
设b为a的差分数组
让a[]全变为0等价于让b[]全变为0
只有操作 1 和操作 2能让b[2, n] 负数变 0 和正数变 0.
先利用操作1和2把b[2, n]全变0,再将b[1]变为0即可
#include
using namespace std;
typedef long long ll;
const int N=2e6+5;
ll a[N],b[N];
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
ll res=0;
for (int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i]-a[i-1];
}
for (int i=2;i<=n;i++)
{
if (b[i]>0) res+=b[i];
else res-=b[i],b[1]+=b[i];
}
res+=abs(b[1]);
cout<<res<<endl;
}
return 0;
}
题意:
有 n 个水库, 当第i个水库满时, 第 i 个水库可以向第 i + 1 个水库倒水(瞬间完成), 最后一个水库会将多余的水瞬间传递到河.
每个水库的容量是 v[i], v为降序排列. 每个水库有一个管道连接. 管道打开时每秒传输 1 升水给水库.
有 q 次询问, 每次询问时所有管道关闭, 水库清空. 求最少需要同时打开多少个管道才可以在 t 时间内填满所有水库.若无法填满, 输出 -1.
题解:
定义 pre[i] 为 v[i] 的前缀和.
为了填满第 i 个水库, 必须消耗 pre[i] / i 的时间
填满所有水库的最少时间为最大的pre[i] / i
如果小于最短事件直接输出-1
实际时间=pre[n]/res<=t,res就是要求的答案,用二分查找答案即可
#include
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
#define endl "\n"
const int N=2e6+5;
double v[N],pre[N];
int main()
{
IOS;
int n;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>v[i];
pre[i]=pre[i-1]+v[i];
}
double mint=0;
for (int i=1;i<=n;i++) mint=max(mint,pre[i]/(1.0*i));
int m;
cin>>m;
while(m--)
{
double t;
cin>>t;
if (t<mint)
{
cout<<-1<<endl;
continue;
}
int l=1,r=n;
while(l<r)
{
int mid=(l+r)/2;
if(pre[n]/(mid*1.0)<=t) r=mid;
else l=mid+1;
}
cout<<r<<endl;
}
return 0;
}