C-有趣的二进制
这题注意两点。
一是因为计算机里存储整数都是补码形式,其次是负数的情况,如果是负数移位后会在最高位补1,那么就不能正确统计个数,而且程序会死循环,所以这里必须转换成usigned long long去做(变成无符号整数)。
#include <bits/stdc++.h>
using namespace std;
int count_one_bits(unsigned long long num)
{
int count = 0;
while(num)
{
if(num&1)
count++;
num>>=1;
}
return count;
}
int main()
{
long long n;
while(~scanf("%lld",&n))
{
int cnt = count_one_bits(n);
printf("%d\n",cnt);
}
return 0;
}
但是吧。。标程的操作秀蒻一脸。。。
#include <bits/stdc++.h>
using namespace std;
int main()
{
for (long long n; cin >> n ; cout << bitset<64>(n).count() << endl) {}
return 0;
}
G-组合数
说实话我让这名字吓到了。。
什么组合数。。。就是个贪心,用优先队列很好解决,每次取长度最短的两个,然后拼接到一起,再将其压入队列,最后size为1的时候就是答案。
#include <bits/stdc++.h>
using namespace std;
struct cmp{//定义优先级,优先长度最小的
bool operator ()(int &a,int &b)
{
return a>b;
}
};
int main()
{
int n,x;
while(~scanf("%d",&n))
{
priority_queue<int,vector<int>,cmp> q;
for(int i = 0; i < n; ++i){
cin>>x,q.push(x);
}
int ans = 0;
while(q.size()!=1)
{
int s = q.top();
q.pop();
int b = q.top();
q.pop();
ans += s+b;
q.push(s+b);
}
cout<<ans<<endl;
}
return 0;
}
I-背包问题
这道题吧。。如果你对动态规划敏感的话,看到这个n的范围就应该想到去用dfs,因为深度只和n有关,n最大只有30。
#include <bits/stdc++.h>
using namespace std;
int w[31],n,m;
int dfs(int dx,int v)
{
if(v==0)//说明正好拿完
return 1;
if(v<0)//容积不够
return 0;
if(dx==n)
return v>=0;//看是否容积足够
return dfs(dx+1,v)+dfs(dx+1,v-w[dx]);//拿与不拿
}
int main()
{
while(~scanf("%d%d",&n,&m)){
for(int i = 0; i < n; ++i)
scanf("%d",&w[i]);
printf("%d\n",dfs(0,m));
}
return 0;
}
J-are you ok?
这道题主要就是加一这个操作,它可能会破坏序列的有序性,所以你需要维护它。。
法一:线段树(蒻不会QAQ)
但是加一只会破坏a[i-1],所以法二。
法二:stl之定义partial_sum(蒻比赛完才知道有这个东西QAQ),具体作用大家找度娘哈~~
#include <bits/stdc++.h>
const int N = 1e6+1;
using namespace std;
int a[N],Max[N];
int main()
{
int n,q,k;
while(~scanf("%d%d",&n,&q))
{
for(int i = 0; i < n; ++i){
scanf("%d",&a[i]);
}
partial_sum(a,a+n,Max,[](int a,int b){ return max(a,b); });//这里是关键1
while(q--)
{
scanf("%d",&k);
int *j = lower_bound(Max,Max+n,k);
if(j==Max+n){
printf("are you ok\n");
}else {
printf("%d\n",j-Max);
}
if(j==Max||j==Max+n)
continue;
if(a[j-Max-1]==Max[j-Max-1])//关键2
(*(j-1))++;
a[j-Max-1]++;
}
}
return 0;
}
K-序列求和
本题本意是要考大家矩阵的知识。。但是正好是有公式的,所以只需要求6的逆元就好了,这里蒻用的费马小定理。
公式推导如下:
利用恒等式(n+1)³=n³+3n²+3n+1,可以得到:
(n+1)³-n³=3n²+3n+1,
n³-(n-1)³=3(n-1)²+3(n-1)+1
.
3³-2³=3*(2²)+3*2+1
2³-1³=3*(1²)+3*1+1.
把这n个等式两端分别相加,得:
(n+1)³-1=3(1²+2²+3²+.+n²)+3(1+2+3+...+n)+n,
由于1+2+3+...+n=(n+1)n/2,
代入上式得:
n³+3n²+3n=3(1²+2²+3²+.+n²)+3(n+1)n/2+n
整理后得:
1²+2²+3²+.+n²=n(n+1)(2n+1)/6
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod = 1e9+7;
ll pow_(ll a, ll n, ll p)
{
ll ans = 1;
ll res = a;
while(n)
{
if(n&1)
ans = ans%p*res%p;
res = res%p*res%p;
n >>= 1;
}
return ans%p;
}
//费马小定理求逆元
ll niYuan(ll a, ll b)
{
return pow_(a,b-2,b);
}
int main()
{
long long n;
while(~scanf("%lld",&n))
{
ll ans = ((((n%mod)*((n+1)%mod))%mod*((2*n+1)%mod))%mod*niYuan(6,mod)%mod)%mod;
printf("%lld\n",ans);
}
return 0;
}
但是如果不会求逆元,本题java大数也可过。
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[]args){
Scanner in = new Scanner(System.in);
BigInteger mod = new BigInteger("1000000007");
BigInteger two = new BigInteger("2");
BigInteger six = new BigInteger("6");
while (in.hasNext()) {
BigInteger n = in.nextBigInteger();
BigInteger ans = n.multiply(n.add(BigInteger.ONE)).multiply(two.multiply(n).add(BigInteger.ONE)).divide(six).mod(mod);
System.out.println(ans);
}
in.close();
}
}