通过这场比赛再次认识到自己的菜,被大佬们吊着锤。。。开场的一个小时节奏还算不错,先过了1004,1009也有思路。接着,服务器就炸了。。。交上去的一发也WA了,比赛中途居然在一直刷网页。。。还好1009把bug找出来A掉了。。。可是1003还是找不出规律啊,1010的dp还是不会优化啊,1001贪心也贪错了啊。。。
不说了,总结起来还是自己太弱了。。。(只能靠赛后补题来防止自己更菜了。。。)
-------------------------------------------------------------------------------------------------------------------------------------------------------
1004 - Find Integer(hdu6441)
题意:找到一组b和c,使得a^n+b^n=c^n。没有输出-1,-1。
这题看一眼应该都想到费马大定理了。n>=3时是无解的。那么只看n=1和n=2即可,n=1是取b=1,c=a+1即可。关键在于n=2时,要想到勾股数的公式(1)当a为大于1的奇数2n+1时,b=2n^2+2n, c=2n^2 +2n+1(2)当a为大于4的偶数2n时,b=n^2-1, c=n^2+1
这个百度就可以了(逃)
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<cstdlib>
using namespace std;
typedef long long ll;
int main()
{
ll t,a,n;
ll b,c;
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld",&n,&a);
if(n>=3||n==0)
printf("-1 -1\n");
else
{
if(n==1)
{
printf("1 %lld\n",a+1);
}
else if(n==2)
{
if(a%2==1)
{
n=a/2;
b=2*n*n+2*n;
c=b+1;
}
else
{
n=a/2;
b=n*n-1;
c=n*n+1;
}
printf("%lld %lld\n",b,c);
}
}
}
return 0;
}
1009 Tree and Permutation(hdu6446)
题意:从给出的序列的一个端点到另一个端点的费用即为s(i),求所有序列的全排列s(i)的和
这题是队友想出来的,Orz果爷。。。
通过观察可以发现只要计算这个序列中任意两点距离的总和 乘上 2(n-1)f(n-2), 其中f(i)代表i的阶乘。
后面是怎么得到的呢?如(1 3)和(3 1)算了两次,所以乘2。后面的可以将此时选出来的两个数看成一个整体,一个组合数就搞定了(很像高中的排列组合题)。。。
那么任意两点间距离怎么算呢?其实对边统计就行了,对每条边而言,经过这条边的总次数就是这条边两边点数的乘积。所以这道题其实1遍dfs即可。。。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<cstdlib>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
const int MAXN = 1e5+9;
int n;
ll ans, f[MAXN], cnt_son[MAXN];
struct node{
int y;
ll l;
};
vector<node>e[MAXN];
void dfs(int fa, int cur){
cnt_son[cur]=1;
ll l=0;
for(int i=0; i<e[cur].size(); ++i){
int son=e[cur][i].y;
if(son==fa){
l=e[cur][i].l;
continue;
}
dfs(cur, son);
cnt_son[cur]+=cnt_son[son];
}
ans=(ans+cnt_son[cur]*(n-cnt_son[cur])%mod*l%mod)%mod;
}
void solve(){
int x, y;
ll l;
node t;
for(int i=1; i<=n; ++i){
e[i].clear();
}
if(1==n){
puts("0");
return;
}
for(int i=1; i<n; ++i){
scanf("%d%d%lld", &x, &y, &l);
t.y=y, t.l=l;
e[x].push_back(t);
t.y=x, t.l=l;
e[y].push_back(t);
}
ans=0;
dfs(-1, 1);
ans=ans*(n-1)%mod*2%mod*f[n-2]%mod;
printf("%lld\n", ans);
}
void init(){
f[0]=1;
for(int i=1; i<MAXN; ++i){
f[i]=f[i-1]*(ll)i%mod;
}
}
int main(){
init();
while(scanf("%d", &n)!=EOF){
solve();
}
return 0;
}
1003 Dream (hdu6440)
题意:不说了(哭),场上读了一小时也不懂,英语弱菜。。。
这题结论好简单啊,就是在加法和乘法基础上取个模就好了。。。
不过你能想到?(大佬请无视)
弱弱的我还是不会证。。。
代码:
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int main()
{
int t,p;
scanf("%d",&t);
while(t--)
{
scanf("%d",&p);
for(int i=0;i<p;i++)
{
printf("%d",(i+0)%p);
for(int j=1;j<p;j++)
{
printf(" %d",(i+j)%p);
}
printf("\n");
}
for(int i=0;i<p;i++)
{
printf("%d",(i*0)%p);
for(int j=1;j<p;j++)
{
printf(" %d",(i*j)%p);
}
printf("\n");
}
}
return 0;
}
1010 YJJ's Salesman (hdu6447)
题意:从(0,0)出发到(1e9,1e9),途中不走回头路且只能向下,右,右下走,且只有想右下走时能拿钱,求最多拿多少钱
dp转移很好像,很明显TLE+MLE。首先必然离散化,由于我太弱了,二维的离散化之前没怎么写过,比赛时很生疏。。。
离散完后思路还是明显的,j表示当前所在列(这里需要从右往左,从上往下扫,和01背包的优化相似)f[j]代表当前列最大值,即f[j]=max(f[1]~f[i]+v[num],f[j])(1=<i<j)
看到了维护区间最大值,线段树或BIT搞一下就可以了
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
using namespace std;
typedef long long ll;
const int MAXN=1e5+10;
typedef struct
{
ll x;
ll y;
ll v;
} Node;
Node node[MAXN];
ll nx[MAXN];
ll ny[MAXN];
ll MAX[MAXN<<2];
ll Max;
int tx,ty;
int t,n;
bool cmp(Node a,Node b)
{
if(a.x==b.x)
return a.y>b.y;
else
return a.x<b.x;
}
void PushUP(int rt) {
MAX[rt] = max(MAX[rt<<1] , MAX[rt<<1|1]);
}
void update(int p,ll sc,int l,int r,int rt) {
if (l == r) {
MAX[rt] = sc;
return ;
}
int m = (l + r) >> 1;
if (p <= m) update(p , sc , lson);
else update(p , sc , rson);
PushUP(rt);
}
ll query(int L,int R,int l,int r,int rt) {
if (L <= l && r <= R) {
return MAX[rt];
}
int m = (l + r) >> 1;
ll ret = 0;
if (L <= m) ret = max(ret , query(L , R , lson));
if (R > m) ret = max(ret , query(L , R , rson));
return ret;
}
int main()
{
int cntx,cnty;
ll tem,ans;
scanf("%d",&t);
while(t--)
{
cntx=cnty=0;
memset(MAX,0,sizeof(MAX));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld",&node[i].x,&node[i].y,&node[i].v);
nx[++cntx]=node[i].x;
ny[++cnty]=node[i].y;
}
sort(nx+1,nx+1+cntx);
sort(ny+1,ny+1+cnty);
tx=unique(nx+1,nx+cntx+1)-(nx+1);
ty=unique(ny+1,ny+cnty+1)-(ny+1);
for(int i=1;i<=n;i++)
{
node[i].x=lower_bound(nx+1,nx+cntx+1,node[i].x)-nx;
node[i].y=lower_bound(ny+1,ny+cnty+1,node[i].y)-ny;
}
sort(node+1,node+1+n,cmp);
printf("%d %d\n",tx,ty);
int y;
ans=0;
for(int i=1;i<=n;i++)
{
y=node[i].y;
if(y!=1)
{
Max=query(y,y,1,n,1);
tem=max(Max,query(1,y-1,1,n,1)+node[i].v);
update(y,tem,1,n,1);
ans=max(ans,tem);
}
else
{
Max=query(y,y,1,n,1);
tem=node[i].v;
update(y,tem,1,n,1);
ans=max(ans,tem);
}
}
printf("%lld\n",ans);
}
return 0;
}
1001 Buy and Resell (hdu6438)
思路:每个地方有一个价格,可以在每个地方选择买,卖,或不买不卖。同时可携带多个商品,初始钱无限,问最多赚多少钱。
和 http://codeforces.com/problemset/problem/867/E差不多,
可以看看这篇题解
https://blog.csdn.net/qq_28954601/article/details/78146932
唯一不同的是这题要求交换次数最小。其实也好像,比如1 -> 2 ->5 -> 10,中间多算了2和5,那么把他们减掉就可以了。也就是对于既卖又买的点减掉即可。。。
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int MAXN=1e5+10;
priority_queue<ll, vector<ll>, greater<ll> > q;
map<ll,int> mp;
int main()
{
int t,n;
ll tem,ans,tt;
int cnt;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
cnt=0;
ans=0;
mp.clear();
while(!q.empty())
q.pop();
for(int i=1;i<=n;i++)
{
scanf("%lld",&tem);
if(q.empty())
{
q.push(tem);
}
else
{
if(q.top()>=tem)
{
q.push(tem);
}
else
{
tt=q.top();
cnt+=2;
q.pop();
q.push(tem);
q.push(tem);
ans+=(tem-tt);
if(mp[tt]>0)
{
mp[tt]--;
cnt-=2;
}
mp[tem]++;
}
}
}
printf("%lld %d\n",ans,cnt);
}
return 0;
}
其实还想补个1007,但由于我太弱了,等过两天再补,待更。。。