1002 Best Solver 即HDU 5451
咋一看,跟人家的那道长沙邀请赛的题目很像。只不过这里的幂是2^x+1
如果能求出幂就好了,x那么大,势必要用快速幂。
事实上可以先求出n=(2^x)%((m-1)*(m+1))+1;
然后用矩阵快速幂。
两个快速幂的结合啊。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
using namespace std;
typedef vector<LL>vec;
typedef vector<vec>mat;
LL m,n,x;
int Case=1;
mat mul(mat &a,mat &b)
{
mat c(a.size(),vec(b[0].size()));
for(int i=0;i<a.size();i++)
for(int k=0;k<b.size();k++)
for(int j=0;j<b[0].size();j++)
c[i][j]=(c[i][j]+a[i][k]*b[k][j])%m;
return c;
}
mat pow(mat a,LL n)
{
mat b(a.size(),vec(a[0].size()));
for(int i=0;i<a.size();i++) b[i][i]=1;
while(n)
{
if(n&1) b=mul(b,a);
a=mul(a,a);
n>>=1;
}
return b;
}
LL quick_mod(LL a,LL n,LL m)
{
LL r=1;
while(n)
{
if(n&1) r=(r*a)%m;
n>>=1;
a=(a*a)%m;
}
return r;
}
void solve()
{
n=quick_mod(2,x,(m-1)*(m+1))+1;
mat a(2,vec(2));
a[0][0]=5;a[0][1]=24;
a[1][0]=1;a[1][1]=5;
a=pow(a,n);
LL ans=(a[0][0]*2-1+m)%m;
printf("Case #%d: %I64d\n",Case++,ans);
}
int main()
{
// freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
scanf("%I64d%I64d",&x,&m);
solve();
}
return 0;
}
1003 即 HDU 5452 Minimum Cut
出题人也是6,一道傻逼题被描述得很难的样子,不光卡题意,还卡常,我大概估计了一下读数据就花了1000+ms,说好的标程三倍时限呢。
题意:给出n个点,然后给出一颗这n个点的生成树的边,最后再给出一些边,这样就成了一个图了,现在,要做的事情就是删掉最少的边,使得图不连通,然后必须删一条生成树的边,生成树的边也只能删一条。
首先,要明确的是,我们要使得图不连通,使得一个点孤立就可以了,那么,而且这个点必然不能是生成树上的非叶子节点。
所以:第一步,找出生成树上的所有叶子节点。
第二步,统计每个顶点连出去的边(非生成树的边)
那么答案就是叶子节点中连边数的最小值
最后答案还要加1,就是因为要删掉一条生成树的边嘛。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
/*
正反循环的宏定义
*/
#define ffr(i,x,y) for(int i=(x),_en=(y);i<=_en;i++)
#define rff(i,x,y) for(int i=(x),_en=(y);i>=_en;i--)
#define clr(f,z) memset(f,z,sizeof(f))
using namespace std;
const int maxn=20005,inf=1<<29;
int dir[][2]={ {0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};//常用方向数组
int n,m,t;//常用全局变量
int in[maxn],a[maxn],b[maxn];
struct node
{
int x,y;
};//常用结构体
vector<int>G[maxn];//常用邻接表
/*
函数重载,可根据参数类型,自动选择输入
*/
bool sf(int &x) { return scanf("%d",&x)==1;}
bool sf(char *x){return scanf("%s",x)==1;}
bool sf(double &x){return scanf("%lf",&x)==1;}
bool sf(LL &x) { return scanf("%I64d",&x)==1;}
void pf(int x,int op) {
op?printf("%d\n",x):printf("%d ",x);//op==0打印数字加空格,op==1打印数字加换行
}
void pf(LL x,int op) {
op?printf("%I64d\n",x):printf("%I64d ",x);//op==0打印数字加空格,op==1打印数字加换行
}
int get_rand(int n)
{
return (int)((double)rand() / RAND_MAX * n) ;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//srand(time(NULL));
sf(t);
int Case=1;
while(t--)
{
sf(n);sf(m);
//ffr(i,0,n) G[i].clear();
clr(a,0);clr(b,0);
ffr(i,1,m)
{
int x,y;
sf(x);sf(y);
if(i>=n) b[x]++,b[y]++;//统计出生成树中顶点连出去的边数
else a[x]++,a[y]++;//统计每个顶点连出去的边数
}
int ans=1<<30;
ffr(i,1,n)
{
if(a[i]>=2) continue;//非叶子节点
ans=min(ans,b[i]);
}
printf("Case #%d: %d\n",Case++,ans+1);
}
return 0;
}
1012 Largest Point 即 HDU 5461 Largest Point
给定n个数 t1,t2,...tn
给定a,b;求a*ti*ti+b*tj的最大值。
拿到这个题我就知道是个傻逼题,我了大去,然而,我一开始傻逼了,想对a,b是否大于0分类讨论。
妈蛋,分类讨论了快一个小时,越讨论,感觉越复杂。就放弃了这种想法,开始想新的算法。
后来,想到了正确做法。
令A[i]=a*ti*ti和B[j]=b*tj;
以o(n)的复杂度算出A,B数组。
然后对A,B数组分别排序。分别取出A,B数组最大的两个数就行了。注意A,B数组不能同时取同一个数。。。
下面是AC代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
/*
正反循环的宏定义
*/
#define ffr(i,x,y) for(int i=(x),_en=(y);i<=_en;i++)
#define rff(i,x,y) for(int i=(x),_en=(y);i>=_en;i--)
#define clr(f,z) memset(f,z,sizeof(f))
using namespace std;
const int maxn=1000005,inf=1<<29;
int dir[][2]={ {0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};//常用方向数组
vector<int>G[maxn];//常用邻接表
/*
函数重载,可根据参数类型,自动选择输入
*/
bool sf(int &x) { return scanf("%d",&x)==1;}
bool sf(char *x){return scanf("%s",x)==1;}
bool sf(double &x){return scanf("%lf",&x)==1;}
bool sf(LL &x) { return scanf("%I64d",&x)==1;}
void pf(int x,int op) {
op?printf("%d\n",x):printf("%d ",x);//op==0打印数字加空格,op==1打印数字加换行
}
void pf(LL x,int op) {
op?printf("%I64d\n",x):printf("%I64d ",x);//op==0打印数字加空格,op==1打印数字加换行
}
int get_rand(int n)
{
return (int)((double)rand() / RAND_MAX * n) ;
}
LL a,b,num[maxn];
LL get(LL x,LL y)
{
return a*x*x+b*y;
}
struct node{
LL x;
int id;
} A[maxn],B[maxn];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//srand(time(NULL));
int n,t,Case=1;
sf(t);
while(t--)
{
sf(n);sf(a);sf(b);
//pf(n,0),pf(a,1),pf(b,1);
ffr(i,0,n-1)
{
sf(num[i]);
A[i].x=a*num[i]*num[i];
A[i].id=i;
B[i].x=b*num[i];
B[i].id=i;
}
sort(A,A+n,cmp);sort(B,B+n,cmp);
LL ans;
if(A[n-1].id!=B[n-1].id) ans=A[n-1].x+B[n-1].x;
else
{
ans=max(A[n-1].x+B[n-2].x,A[n-2].x+B[n-1].x);
}
printf("Case #%d: %I64d\n",Case++,ans);
}
return 0;
}