HIT第一周 周测补题

A    HDU 5950 

题意:f(n)=f(n-1)+2*f(n-2)+n4,f(1)=a,f(2)=b,求f(n)。

思路:因为(n+1)4=n4+4n3+6n2+4n+1,据此构造矩阵,做矩阵快速幂。

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=7;
const ll mod=2147493647;
struct Mat
{
    ll m[N][N];
};
Mat c={1,2,1,4,6,4,1,
       1,0,0,0,0,0,0,
       0,0,1,4,6,4,1,
       0,0,0,1,3,3,1,
       0,0,0,0,1,2,1,
       0,0,0,0,0,1,1,
       0,0,0,0,0,0,1};
Mat mul(Mat a,Mat b)
{
    int i,j,k;
    Mat tmp;
    memset(tmp.m,0,sizeof(tmp.m));
    for(i=0;i<N;i++)
    for(j=0;j<N;j++)
    for(k=0;k<N;k++)
        tmp.m[i][j]=(tmp.m[i][j]+a.m[i][k]*b.m[k][j]%mod)%mod;
    return tmp;
}
Mat pow(Mat a,int k)
{
    Mat ans;
    memset(ans.m,0,sizeof(ans.m));
    for(int i=0;i<N;i++) ans.m[i][i]=1;
    while (k)
    {
        if (k&1) ans=mul(ans,a);
        a=mul(a,a);
        k>>=1;
    }
    return ans;
}
int main()
{
    ll a,b,ans;
    int t,i,n,now;
    Mat tmp;
    while (scanf("%d",&t)!=EOF)
    {
        while (t--)
        {
            scanf("%d%lld%lld",&n,&a,&b);
            a=a%mod;b=b%mod;
            if (n==1) printf("%lld
",a);
            else if (n==2) printf("%lld
",b);
            else 
            {
                tmp=pow(c,n-2);
                ans=(tmp.m[0][0]*b%mod+tmp.m[0][1]*a%mod)%mod;
                now=1;
                for (i=6;i>=2;i--)
                {
                    ans=(ans+tmp.m[0][i]*now%mod)%mod;
                    now=now*2;
                }//初始 {b,a,16,8,4,2,1} 
                printf("%lld
",ans);
            }
            
        }
    }
    return 0;
}
View Code

B    CodeForces 1143D

(看题看到头大)

D    POJ 1220

进制转化

E    LibreOJ 10017

三分

F    CodeForces 1132D

题意:有n台电脑,其中第n台电脑初始时有a[i]的电量,每分钟花费b[i]的电量。有一个充电器,每次只能给一个一台电脑充电,要保证在T时间内所有电脑在任意分钟都有电(电量不小于0),问这个充电器每分钟的充电量最小是多少。

思路:二分充电器每分钟充电量。

检验时用一个优先队列,初始时按num[i]=a[i]/b[i]从小到大排序(不充电能用的最长时间),

在0~T的每一分钟都给排在优先队列最前面的电脑充电,更新剩余电量a[i]与能用的最长时间num[i]再将其放回优先队列,

如果有某一分钟中出现给队列最前面的电脑充完电后,排在第二的电脑在前一分钟电量耗尽(num<i),则返回0。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=200005;
const ll inf=2e12+1;
struct node
{
    ll a,b,num;
    bool operator < (const node &a)const{return num>a.num;}
};
int n,T;
node e[maxn];
int jud(ll mid)
{
    int i;
    node x;
    priority_queue<node>q;
    for (i=1;i<=n;i++) q.push(e[i]);
    for (i=1;i<T;i++)
    {
        x=q.top();
        q.pop();
        x.num=x.num+(x.a+mid)/x.b;
        x.a=(x.a+mid)%x.b;
        q.push(x);
        if (q.top().num<i) return 0;
    }
    return 1;
}
ll solve(ll l,ll r)
{
    ll mid;
    while (l<=r)
    {
        mid=(l+r)>>1;
        if (jud(mid)) r=mid-1;
        else l=mid+1;
    }
    return l;
}
int main()
{
    int i;
    scanf("%d%d",&n,&T);
    for (i=1;i<=n;i++) scanf("%I64d",&e[i].a);
    for (i=1;i<=n;i++) 
    {
        scanf("%I64d",&e[i].b);
        e[i].num=e[i].a/e[i].b;
        e[i].a=e[i].a%e[i].b;
    }
    ll ans=solve(0,inf);
    if (!jud(inf)) printf("-1
");
    else printf("%I64d
",ans);
    return 0;
} 
View Code

G    CodeForces 287E

因为要求匹配的一组数中负数要在后面,所以从后往前做。遇到确定为负数的将其压入栈中,遇到不确定的就与当前的栈顶比对,如果可以匹配就将栈顶弹出(贪心),不能匹配就可以确定这个数是负数。

#include<cstdio>
#define maxn 1000005
int a[maxn],stk[maxn],top;
int main()
{
    int i,n,t,x;
    while (scanf("%d",&n)!=EOF)
    {
        for (i=1;i<=n;i++) scanf("%d",&a[i]);
        scanf("%d",&t);
        for (i=1;i<=t;i++)
        {
            scanf("%d",&x);
            a[x]=-a[x];
        }
        for (i=n;i>=1;i--)
        {
            if (a[i]<0) stk[++top]=a[i];
            else 
            {
                if (a[i]+stk[top]==0) top--;
                else 
                {
                    a[i]=-a[i];
                    stk[++top]=a[i];
                }
             } 
        }
        if (top) printf("NO
");
        else 
        {
            printf("YES
");
            for (i=1;i<=n;i++) printf("%d ",a[i]);
            printf("
");
         } 
    }
    return 0; 
}
View Code

H    LibreOJ 10144

使用set,如果当前set中的类型与输入类型a相同,就将b插入set;如果当前set中类型与a不同,就用lower_bound函数找出set中第一个大于等于b的数和第一个小于b的数,按照题意,比较两个数与b差的绝对值,将绝对值较小的计入答案,并在set中删除该数。

#include<cstdio>
#include<set>
#include<cmath>
using namespace std;
const int inf=0x7fffffff;
const int mod=1000000;
set<int>s;
int main()
{
    int a,b,n,ma,mi,now,ans;
    while (scanf("%d",&n)!=EOF)
    {
        s.clear();
        s.insert(inf);
        s.insert(-inf);
        ans=0;
        while (n--)
        {
            scanf("%d%d",&a,&b);
            if (s.size()==2) now=a;
            if (a!=now)
            {
                ma=*s.lower_bound(b);//第一个大于等于b的数 
                mi=*--s.lower_bound(b);// 第一个小于b的数
                if (b-mi<=ma-b && mi!=-inf)
                {
                    ans=(ans+abs(b-mi))%mod;
                    s.erase(mi);
                }
                else if (ma!=inf)
                {
                    ans=(ans+abs(ma-b))%mod;
                    s.erase(ma);
                } 
            }
            else s.insert(b);
        }
        printf("%d
",ans);
    } 
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lsykk/p/13416200.html