n^n的末位数字 (51Nod - 1004)
题意:传送门
思路与小结:
嗯,快速幂,然后只要最后一位数,于是我觉得可以不用longlong,但忘了先模再快速幂,WA了一次。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
#define INF 0x3fffffff
#define MOD 10
long long n;
long long pow(long long x,long long y)
{
long long t=1LL;
while(y)
{
if(y&1)
t*=x,t%=MOD;
x*=x;
x%=MOD;
y=y>>1LL;
}
return t;
}
int main()
{
scanf("%lld",&n);
printf("%lld\n",pow(n,n));
}
蜥蜴和地下室 (51Nod - 1489)
题意:传送门
思路与小结
首先样例把我看懵了,然后发现原来血量为0不算死亡,一定要小于零。所以直接dfs暴力,考虑当前位置i,我们要保证位置i-1的弓箭手死了,所以有一个下界,又要保证是最少次数,所以有一个上界。在上界和下界之间进行枚举,然后递归进入下一个位置。数据特别小,暴力可以过。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
#define INF 0x3fffffff
#define MAXN 50050
int em[110],ans,n,a,b;
void dfs(int x,int sum)
{
if(sum>=ans)
return;
if(x==n-1)
{
int lasta=em[n-1]<0?0:em[n-1]/b+1,lastb=em[n-2]<0?0:em[n-2]/a+1;
sum+=max(lasta,lastb);
ans=min(ans,sum);
return;
}
int l=em[x-1]<0?0:em[x-1]/b+1,r=em[x]<0?0:em[x]/a+1;
r=max(l,r);
for(int i=l;i<=r;i++)
{
em[x]-=a*i;
em[x+1]-=b*i;
dfs(x+1,sum+i);
em[x]+=a*i;
em[x+1]+=b*i;
}
}
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int i=0;i<n;i++)
scanf("%d",&em[i]);
ans=INF;
dfs(1,0);
printf("%d",ans);
}
前缀后缀集合 (51Nod - 1280)
题意:传送门
思路与小结
这道题一开始,我除了暴力是没有其他想法的。我的暴力自认为时间复杂度是 O(n2) O ( n 2 ) 妥妥地T掉,但是呢,我仔细一想似乎并不用那么复杂。我的方法是可以进行优化的,遂成功做到 O(n) O ( n ) ?(或者 O(n∗log(n) O ( n ∗ l o g ( n ) )
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
using namespace std;
#define INF 0x3fffffff
#define MAXN 50050
int n;
int a[MAXN];
long long ans;
map<int,int> vis;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int j=n,last=0,now=0;
for(int i=1;i<=n;i++)
{
if(vis.count(a[i]))
{
ans+=now;
continue;
}
vis[a[i]]=1;
last++; now=0;
while(j>=1&&vis.count(a[j]))
{
if(vis[a[j]]==1)
{
vis[a[j]]=2;
last--;
}
if(last==0)
{
ans++;
now++;
}
j--;
}
}
printf("%lld\n",ans);
}
山峰和旗子 (51Nod - 1281)
题意:传送门
思路与小结
首先我们用 O(n) O ( n ) 的时间把山峰弄出来,然后我们可以发现答案是满足单调性的。然后二分答案就好了,版题。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
#define INF 0x3fffffff
#define MAXN 50050
int n;
int a[MAXN];
vector <int> E;
bool check(int k)
{
if(!k)
return 1;
if(k==1)
return E.size()?1:0;
int last=0;
vector<int>::iterator it;
for(int i=1;i<k;i++)
{
it=lower_bound(E.begin(),E.end(),last+k);
if(it==E.end())
return 0;
last=*it;
}
return 1;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=2;i<n;i++)
if(a[i]>a[i-1]&&a[i]>a[i+1])
E.push_back(i-1);
int l=0,r=n;
while(r-l>1)
{
int mid=(l+r)>>1;
if(check(mid))
l=mid;
else
r=mid;
}
printf("%d",l);
}
最长等差数列 (51Nod - 1055)
题意:传送门
思路与小结
不得不说我的做题顺序有些慌乱,先做了F题后,就去写G题的线段树模版,然后发现自己没有更进一步的思路了。心想:难道这场考试就这样了?然后一点排名,发现我E题还没做,如果不是后来看了我应该不会意识到我没做。
这道题仔细想了一下,可以用Dp来做。利用等差中项的性质。
d[i][j]表示第i个数和第j个数都是等差数列中的数,然后这种情况下的最长等差数列的长度。
因为如果a[i]+a[k]==2*a[j],那么第k个数就可以和它们形成等差数列。d[j][k]=d[i][j]+1;最终答案取max就好了。
顺便说一下,先要排序。以及为了不爆内存,要用short int
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
using namespace std;
#define INF 0x3fffffff
#define MAXN 10005
int n,ans=1;
int a[MAXN];
short int d[MAXN][MAXN];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
for(int i=2;i<=n;i++)
{
int j=i-1,k=i+1;
while(j>0&&k<=n)
{
if(a[j]+a[k]>2*a[i])
j--;
else if(a[j]+a[k]<2*a[i])
k++;
else
{
if(d[j][i]==0)
d[j][i]=d[i][k]=3;
else
d[j][i]=d[i][k]=d[j][i]+1;
ans=max(ans,(int)d[i][k]);
j--,k++;
}
}
}
printf("%d",ans);
}
零树 (51Nod - 1424)
题意:传送门
思路与小结
对于一个节点,我们先考虑它的儿子,然后再对剩下的部分进行操作。开两个数组,一个是+1的次数,一个是-1的次数,分别通过儿子中最大的那一个转移过来。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
using namespace std;
#define INF 0x3fffffff
#define MAXN 100050
int n;
long long d[MAXN],up[MAXN],down[MAXN];
vector<int> E[MAXN];
void dfs(int x,int f)
{
for(int i=0;i<E[x].size();i++)
{
int t=E[x][i];
if(t!=f)
{
dfs(t,x);
up[x]=max(up[x],up[t]);
down[x]=max(down[x],down[t]);
}
}
d[x]+=up[x]-down[x];
if(d[x]>0)
down[x]+=d[x];
if(d[x]<0)
up[x]-=d[x];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
E[a].push_back(b);
E[b].push_back(a);
}
for(int i=1;i<=n;i++)
scanf("%lld",&d[i]);
dfs(1,-1);
printf("%lld",up[1]+down[1]);
}