A AtCoder 3952
题解
计算前缀和,然后搞一下就出来了。
代码
#include<bits/stdc++.h>
using namespace std;
const int nmax = 2e5+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
map<ll,ll> mpall;
map<ll,ll> mpfront;
int n;
ll a[nmax];
ll prefix[nmax];
int main(){
scanf("%d",&n);
for(int i = 1;i<=n;++i){
scanf("%lld",&a[i]);
if(i == 1) prefix[i] = a[i];
else {
prefix[i] = prefix[i-1] + a[i];
}
mpall[prefix[i]] ++;
}
ll sum = 0;
ll cnt = 0;
for(int i = 1;i<=n;++i){
cnt += mpall[sum] - mpfront[sum];
mpfront[prefix[i]] ++;
sum += a[i];
}
printf("%lld\n",cnt);
return 0;
}
B HDU - 5701
题解
和BZOJ那个中位数图很像,这道题时限开到6S,并且数据的组数并不是很多,所以直接 的暴力就可以过。不过在比赛的时候,我用的map存储的,所以导致时间复杂度上面多了一个 .这就十分恐怖了,根据数据范围,多一个 会导致时间是原来为10倍,导致超时。
代码
#include<cstdio>
#include<cstring>
using namespace std;
const int nmax = 8050;
const int INF = 0x3f3f3f3f;
const int shift = 8005;
typedef long long ll;
//map<int,int> Lcnt,Rcnt;
//map<int,int> :: iterator it;
int n;
int a[nmax];
int tag[nmax];
int Lcnt[nmax<<1];
int Lprefix[nmax<<1],Rprefix[nmax<<1];
int main(){
while(scanf("%d",&n)!=EOF){
for(int i = 1;i<=n;++i) scanf("%d",&a[i]);
for(int i = 1;i<=n;++i){ //midpos
// Lprefix[i] = Rprefix[i] = 0;
int prefix = 0;
memset(Lcnt,0,sizeof Lcnt);
int temp = 1;
for(int j = i-1;j>=1;--j){ //l
tag[j] = a[j] > a[i] ? 1 : -1;
// Lprefix[j] = Lprefix[j+1] + tag[j];
prefix += tag[j];
Lcnt[prefix + shift] ++;
}
prefix = 0;
temp += Lcnt[0+shift];
for(int j = i+1;j<=n;++j){//r
tag[j] = a[j] > a[i] ? 1 : -1;
// Rprefix[j] = Rprefix[j-1] + tag[j];
prefix += tag[j];
if(!prefix) temp++;
// if(Rprefix[j] == 0) temp++;
temp += Lcnt[-prefix + shift];
}
// printf("\n%d: ",i);
// for(int i = 1;i<=n;++i) printf("%d ",Lcnt[i]); printf("\n");
if(i!=n) printf("%d ",temp);
else printf("%d\n",temp);
}
}
return 0;
}
C AtCoder - 3953
题解
字符串哈希,还不会,等着补
D CodeForces - 148D
题解
概率DP, 表示有i个白色棋子,j个黑色棋子的胜利概率,然后推一推把3种情况都推出来就好了。
代码
#include<bits/stdc++.h>
using namespace std;
const int nmax = 1e6 ;
const int INF = 0x3f3f3f3f;
typedef long double ldb;
int w,b;
double dp[1005][1005];
int main() {
while(scanf("%d%d",&w,&b)!=EOF){
memset(dp,0,sizeof dp);
for(int i = 1;i<=1000;++i) dp[i][0] = 1, dp[0][i] = 0;
for(int i = 1;i<=w;++i){
for(int j = 1;j<=b;++j){
dp[i][j] = 1.0 * i / (i+j);
if(i>=1 && j >=2) dp[i][j] += (1.0 * j / (i+j)) * (1.0 * (j-1) / (i + j - 1)) * (1.0 * (i) / (i + j - 2)) * dp[i-1][j-2];
if(i>=0 && j >=3) dp[i][j] += (1.0 * j / (i+j)) * (1.0 * (j-1) / (i + j - 1)) * (1.0 * (j-2) / (i + j -2)) * dp[i][j-3];
}
}
printf("%.10f\n",dp[w][b]);
}
return 0;
}
E CodeForces - 449B
题解
首先要知道如果从1到任意节点x,如果有铁路的话,最多有一条,并且我们只保留那一条最小的,这样的话,我们跑一边最短路,看看最短距离和铁路之间的关系,如果铁路在最短路径上,保留即可,不在则删掉。
代码
#include<bits/stdc++.h>
using namespace std;
const int nmax = 1e5 + 10 ;
const int INF = 1e12;
typedef long long ll;
int n,m,k;
typedef struct{
int to, nxt;
ll w;
}Edge;
Edge e[ (4 * nmax)<<1 ];
typedef pair<int,ll> pii;
vector<pii> ee[nmax];
ll dis[nmax];
int head[nmax<<1],cnt;
bool istrain[nmax],visit[nmax];
inline void add(int & u, int & v, ll & w){
e[cnt].to = v, e[cnt].nxt = head[u], e[cnt].w = w;
head[u] = cnt++;
}
int spfa(int s){
// int CNT = 0;
// bitset<nmax> visit; visit.reset();
queue<int> q; q.push(s); visit[s] = 1;
for(int i = 1;i<=n;++i) dis[i] = i == s? 0 : INF;
for(int i = 1;i<=k;++i){
int v;
ll w;
scanf("%d %I64d",&v,&w);
if(dis[v] == INF) dis[v] = w, istrain[v] = true,q.push(v),visit[v] = 1;
else if(dis[v] >= w){
dis[v] = w;
// CNT ++;
}
}
while(!q.empty()){
int u = q.front(); q.pop(); visit[u] = 0;
for(int i = 0;i < ee[u].size() ;++i){
int v = ee[u][i].first; ll w = ee[u][i].second;
if(dis[u] + w <= dis[v]){
dis[v] = dis[u] + w;
if(istrain[v]) istrain[v] = false;
if(!visit[v]){
q.push(v);
visit[v] = 1;
}
}
}
}
int K = k;
for(int i = 1;i<=n;++i) K -= istrain[i];
return K;
}
int main() {
scanf("%d%d%d",&n,&m,&k);
memset(head,-1,sizeof head);
for(int i = 1;i<=m;++i){
int u,v;
ll w;
scanf("%d %d %I64d",&u,&v,&w);
ee[u].push_back(make_pair(v,w));
ee[v].push_back(make_pair(u,w));
// add(u,v,w);
// add(v,u,w);
}
printf("%d\n",spfa(1));
return 0;
}
F AtCoder - 4143
题解
还没补