@Asuna
2017-04-15T01:53:20.000000Z
字数 4460
阅读 824
题解
题意:求某个点到各点的代价,两点间某条路径的代价定义为路径上权值最大的边的权值,而两点间的权值表示为它们之间所有路径代价的最小值。
题解:dist[u]表示从原点到点u的路径的代价,用Dijkstra。最后注意判断重边。
参考代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<queue>
using namespace std;
typedef pair <int, int> p;
int dist[510];
priority_queue < p, vector<p>, greater<p> > qu;
struct node
{
int nxt;
int w;
int to;
}edge[40000];
bool vis[510];
int head[510],tot;
void addedge(int from, int to, int w)
{
edge[tot].to=to;
edge[tot].w=w;
edge[tot].nxt=head[from];
head[from]=tot++;
}
void Dijkstra(int u, int n)
{
while (!qu.empty())
{
qu.pop();
}
for (int i=0; i<n; i++)
{
dist[i]=100000000;
}
dist[u]=0;
qu.push(make_pair(dist[u], u));
while (!qu.empty())
{
p tmp=qu.top();
qu.pop();
int s=tmp.second;
int d=tmp.first;
for (int i=head[s]; ~i; i=edge[i].nxt)
{
int t=edge[i].to;
int w=edge[i].w;
if (dist[t]>max(d, w))
{
dist[t]=max(d, w);
qu.push(make_pair(dist[t], t));
}
}
}
}
int main() {
int t, icase=1;
scanf("%d", &t);
while (t--)
{
int n, m;
scanf("%d%d", &n, &m);
for (int i=0; i<n; i++)
{
head[i]=-1;
}
tot=0;
int u, v, w;
for (int i=1; i<=m; i++)
{
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
scanf("%d", &u);
Dijkstra(u, n);
printf("Case %d:\n", icase++);
for (int i=0; i<n; i++)
{
if (dist[i]==100000000)
{
printf("Impossible\n");
}
else
{
printf("%d\n", dist[i]);
}
}
}
return 0;
}
题意:给定两个数a,b,求a到b所有数的0的个数。
题解:dp[位数][0~9][0的个数]; 然后记忆化搜索的时候 dfs(第几位,前面有没有非0的数,取数的限制,0的个数);
参考代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long n, m;
long long cal(long long x)
{
if (x<0) return 0;
long long ans=1, cnt=1, tmp=0;
while (x>=10)
{
long long cur=x%10;
x/=10;
if (cur!=0) ans+=x*cnt;
else ans+=(x-1)*cnt+tmp+1;
tmp+=cur*cnt;
cnt*=10;
}
return ans;
}
int main()
{
int t,icase=1;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&m);
printf("Case %d: %lld\n", icase++,cal(m)-cal(n-1));
}
return 0;
}
题意:求(1^K + 2^K + 3^K + ... + N^K)%2^32
题解:矩阵快速幂,由于不知道怎么搞数学公式在这个上面。。。找了篇网上写的比较详细的题解。。http://blog.csdn.net/kg20006/article/details/51057305需要注意的就是转移矩阵还有mod 2^32可以用自然溢出完成。
ps:似乎是伯努利数?有兴趣可以baidu一下伯努利数的相关题目,似乎还蛮多的好像也有点用但是我看不怎么懂。。。。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const long long mod=((long long)1<<32);
long long k,siz,n,C[60][60];
struct Matrix
{
long long a[53][53];
Matrix()
{
memset(a, 0, sizeof(a));
for(int i=1; i<=52; i++)
{
a[i][i]=1;
}
}
};
Matrix operator * (const Matrix & m1, const Matrix & m2)
{
Matrix m;
for(int i=1; i<=siz; i++)
{
for(int j=1; j<=siz; j++)
{
m.a[i][j]=0;
for(int k=1; k<=siz; k++)
{
m.a[i][j]=(m.a[i][j]+(m1.a[i][k]*m2.a[k][j])%mod)%mod;
}
}
}
return m;
}
Matrix quick_pow(Matrix base, long long pow)
{
Matrix A;
while(pow)
{
if(pow&1)
{
A=A*base;
}
base=base*base;
pow>>=1;
}
return A;
}
int main()
{
long long t;
memset(C,0,sizeof(C));
C[0][0]=1;
C[1][0]=C[1][1]=1;
for(int i=2; i<=50; i++)
{
for(int j=0; j<=i; j++)
{
if (j==0)
{
C[i][j]=1;
}
else
{
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
}
scanf("%lld",&t);
for (long long cas=1; cas<=t; cas++)
{
scanf("%lld%lld",&n,&k);
siz=k+2;
Matrix tran;
memset(tran.a, 0, sizeof(tran.a));
for(int i=1; i<=k+1; i++)
{
for(int j=1; j<=k+1; j++)
{
if(i<=j)
{
tran.a[i][j]=C[k+1-i][j-i];
}
}
}
for(int i=1; i<=k+1; i++)
{
tran.a[k+2][i]=C[k][i-1];
}
tran.a[k+2][k+2]=1;
Matrix ans=quick_pow(tran,n-1);
long long ans1=0;
for(int i=1; i<=k+2; i++)
{
ans1=(ans1+ans.a[k+2][i])%mod;
}
printf("Case %lld: %lld\n",cas,ans1);
}
return 0;
}
题意:给一个动态的序列,每次询问序列中第k个元素是啥,询问完以后,就删除这个元素,同时可以在结尾添加元素,如果当前位置没有元素,就输出“none”。
题解:区间修改+区间询问+单点修改的线段树。一开始毫无头绪,好在mzjj和js提示了许多。。总的来说树上维护的东西是当前区间内还有多少个元素没被删除,这样当询问到某一棵子树的时候,如果左子树的元素个数大于k,那么元素必定在左子树当中,否则就在右子树当中,在左子树当中固然好,就是左子树区间内第k个,在右子树的话就应该是第k减去左子树元素个数个,同时在叶子结点维护元素值。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int num[800010],id[800010],ans;
void pushup(int rt)
{
num[rt]=num[rt*2]+num[rt*2+1];
}
void build(int l,int r,int rt)
{
num[rt]=0;
id[rt]=-1;
if (l==r) return;
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
}
void update(int x,int c,int l,int r,int rt)
{
if (l==r)
{
num[rt]=1;
id[rt]=c;
return;
}
int mid=(l+r)/2;
if (x<=mid) update(x,c,l,mid,rt*2);
else update(x,c,mid+1,r,rt*2+1);
pushup(rt);
}
void query(int k, int l, int r, int rt)
{
num[rt]-=1;
if (l==r)
{
ans=id[rt];
id[rt]=-1;
return;
}
int mid=(l+r)/2;
if (num[rt*2]>=k) query(k,l,mid,rt*2);
else
{
k-=num[rt*2];
query(k,mid+1,r,rt*2+1);
}
}
int main()
{
int t,icase=1;;
scanf("%d",&t);
while(t--)
{
int n,m,sum;
scanf("%d%d",&n,&m);
sum=n+m;
build(1,sum,1);
printf("Case %d:\n",icase++);
for (int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
update(i,x,1,sum,1);
}
while (m--)
{
char s[2];
int x;
scanf("%s%d",s,&x);
if (s[0]=='a')
{
n+=1;
update(n,x,1,sum,1);
}
else
{
query(x,1,sum,1);
if (ans==-1) printf("none\n");
else printf("%d\n",ans);
}
}
}
return 0;
}