ID | Origin | Title | |
---|---|---|---|
Problem A | URAL 1900 | Brainwashing Device | |
Problem B | URAL 1901 | Space Elevators | |
Problem C | URAL 1902 | Neo-Venice | |
Problem D | URAL 1903 | Unidentified Ships | |
Problem E | URAL 1904 | The Lessons of the Past | |
Problem F | URAL 1905 | Travel in Time | |
Problem G | URAL 1906 | The Lost Civilization | |
Problem H | URAL 1907 | Coffee and Buns | |
Problem I | URAL 1908 | Brute-force Search | |
Problem J | URAL 1909 | Space Recon |
题目异常难懂。。还有就是代码能力太差了,往往出题速度和想题速度不成正比。。。导致出题异常的慢。。。得注意提高代码能力了,唉
A题比较容易懂,是一道输出路径的dp。
B题要求的是电梯最多坐两个人,每次重要值之和不超过s,求最多的次数。直接贪心就可以了。
C题是一道很水的题目。。
D题我没看。。队友做的。组合数学,不过需要注意的是开5000*5000的数组会MLE。而且仔细想想是不需要开那么大的数组的,组合数只要求3列就行了。。粘上队友的代码。
E题到最后都没看懂题目。。。队友猜了一个题意,很晚才ac的。。
F题要求在同一个位置不能同一个时间待两次,只要我们按最短路求,那就肯定不会出现这种情况。因为假如第一次就可以走那条路,那第二次同一时间到达这里就完全没必要了。另为注意一些优化,不然程序会退化到O(m^2)。(优化见代码部分)
A题比较容易懂,是一道输出路径的dp。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 550;
int out[maxn], pt[maxn][maxn];
int a[maxn][maxn], dp[maxn][maxn], add[maxn][maxn];
int main()
{
int n, k;
while(scanf("%d%d", &n, &k) != EOF)
{
CLR(a, 0);
for(int i = 1; i < n; i ++)
{
for(int j = i + 1; j <= n; j ++)
{
scanf("%d", &a[i][j]);
}
}
for(int i = 1; i <= n; i ++)
{
out[i]= 0;
for(int j = 1; j <= n; j ++)
{
out[i] += a[i][j];
}
}
CLR(add, 0);
for(int i = 0; i <= n; i ++)
{
int tot = 0, sub = 0;
for(int j = i + 1; j <= n; j ++)
{
tot += out[j];
for(int s = i + 1; s <= j; s ++)
sub += a[s][j];
add[i][j] = tot - sub;
}
}
CLR(dp, 0);
for(int j = 1; j <= k; j ++)
{
for(int i = 1; i < n; i ++)
{
for(int l = 0; l < i; l ++)
{
int tmp1 = dp[j - 1][l] + add[l][i] , &tmp2 = dp[j][i];
if(tmp1 >= tmp2)
{
tmp2 = tmp1;
pt[j][i] = l;
}
}
}
}
int ans = 0, id;
for(int i = 1; i <= n; i ++)
if(dp[k][i] >= ans) ans = dp[k][i], id = i;
printf("%d\n", ans);
vector<int> path;
for(int i = k; i; i --)
{
path.push_back(id);
id = pt[i][id];
}
sort(path.begin(), path.end());
for(int i = 0; i < k; i ++)
{
printf("%d%c", path[i], i == k - 1 ? '\n' : ' ');
}
}
}
B题要求的是电梯最多坐两个人,每次重要值之和不超过s,求最多的次数。直接贪心就可以了。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 100100;
const int INF = 123456789;
vector<int> los, ans;
int v[maxn];
int main()
{
int n, s;
while(scanf("%d%d", &n, &s) != EOF)
{
int tot = 0;
for(int i = 0; i < n; i ++)
{
scanf("%d", &v[i]);
}
sort(v, v + n);
int l = 0, r = n - 1;
ans.clear();los.clear();
while(l < r)
{
if(v[l] + v[r] <= s)
{
los.push_back(v[l]);
l ++;
}
else
{
ans.push_back(v[l ++]);
ans.push_back(v[r --]);
}
}
if(l == r) los.push_back(v[l]);
sort(los.begin(), los.end());
for(int i = los.size() - 1; i >= 0; i --)
ans.push_back(los[i]);
for(int i = 0; i < n; i ++)
{
if(ans[i] + ans[i + 1] <= s) i ++;
tot ++;
}
printf("%d\n", tot);
for(int i = 0; i < n; i ++)
{
printf("%d%c", ans[i], i == n - 1 ? '\n' : ' ');
}
}
}
C题是一道很水的题目。。
D题我没看。。队友做的。组合数学,不过需要注意的是开5000*5000的数组会MLE。而且仔细想想是不需要开那么大的数组的,组合数只要求3列就行了。。粘上队友的代码。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cstdio>
#include <cmath>
#include <stack>
#include<map>
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define maxn 5100
#define E exp(double(1))
#define eps 1e-7
using namespace std;
#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif
LL mod = 1000000007;
LL str[maxn];
LL s[maxn];
LL ext_gcd(LL a,LL b,LL &x,LL &y){
LL t,ret;
if(!b){
x=1,y=0;
return a;
}
ret=ext_gcd(b,a%b,x,y);
t=x,x=y,y=t-a/b*y;
return ret;
}
//逆元(b/a)%mod
LL inv(LL a,LL b,LL mod){
LL x,y;
ext_gcd(a,mod,x,y);
return (x*b%mod+mod)%mod;
}
void init(){
str[0]=1;
for(int i=1;i<=5001;i++){
str[i]=str[i-1]*i%mod;
s[i]=inv(str[i],1,mod);
}
}
LL fun(LL m,LL n) {
if(n>m)return 0;
if(n==0||m==0||n==m)return 1;
return (str[m]*s[n]%mod)*s[m-n]%mod;
}
LL c[maxn];
int main(){
LL k,n,t,x;
init();
while(scanf("%lld%lld",&n,&t)!=EOF){
for(int i=1;i<=n;i++){
scanf("%lld",&c[i]);
}
scanf("%lld%lld",&k,&x);
LL val = c[k];
LL s1=0,s2=0,ss=0;
for(int i=1;i<=n;i++){
if(c[i]>val)s2++;
if(c[i]<val)s1++;
if(c[i]==val)ss++;
}
LL ans = 0;
LL l = x-1;
LL r = t-x;
for(int i=max(0LL,x-1-s1);i<ss&&i<=l;i++){
for(int j=max(t-x-s2,0LL);j<ss-i&&j<=r;j++){
LL q = fun(ss-1,i+j) *fun(s1,x-1-i)%mod*fun(s2,t-x-j)%mod;
ans+=q;
ans%=mod;
}
}
printf("%lld\n",ans);
}
return 0;
}
E题到最后都没看懂题目。。。队友猜了一个题意,很晚才ac的。。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cstdio>
#include <cmath>
#include <stack>
#include<map>
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define maxn 400000
#define E exp(double(1))
#define eps 1e-7
using namespace std;
#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif
int ans[maxn];
int h[maxn];
struct as{
int s,t;
as(){}
as(int s,int t):s(s),t(t){}
};
vector<as>v;
int main(){
int i,j,k;
int n,cnt;
while(scanf("%d",&n)!=EOF){
memset(ans,0,sizeof ans);
for(int i=0;i<n;i++){
scanf("%d",&h[i]);
}
for(int i=-12000;i<12000;i++){
int pos = i+12000;
int now = i;
for(int j=0;j<n;j++){
now = abs(now - h[j]);
}
if(now ==0 ||now==1)ans[pos]=true;
}
int cnt = 0;
v.clear();
int l,r;
for(int i=-12000;i<12000;){
int pos = i+12000;
if(ans[pos]){
l = pos;
r=l;
while(ans[r]==true)r++;
v.push_back(as(l,r-1));
i=r-12000;
}else{
i++;
}
}
printf("%d\n",v.size());
for(int i=0;i<v.size();i++){
printf("%d %d\n",v[i].s-12000,v[i].t-12000);
}
}
return 0;
}
F题要求在同一个位置不能同一个时间待两次,只要我们按最短路求,那就肯定不会出现这种情况。因为假如第一次就可以走那条路,那第二次同一时间到达这里就完全没必要了。另为注意一些优化,不然程序会退化到O(m^2)。(优化见代码部分)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cstdio>
#include <cmath>
#include <stack>
#include<map>
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define maxn 100100
#define eps 1e-7
using namespace std;
#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif
struct Edge
{
int u, v, b, e, id, fa;
bool operator < (const Edge &rhs) const
{
return b < rhs.b;
}
void pt()
{
printf("%d %d %d %d %d\n", u, v, b, e, id);
}
}E[maxn];
int fir[maxn], nxt[maxn], tot;
void AddEdge(int u, int v)
{
nxt[tot] = fir[u]; fir[u] = tot ++;
}
int n, m, sid, eid, stm, etm;
bool vis[maxn];
int bfs()
{
queue<int> Q;memset(vis, false, sizeof(vis));
for(int i = fir[sid]; ~i; i = nxt[i]) if(E[i].b >= stm)
{
Q.push(i);vis[i] = true;
}
while(!Q.empty())
{
int now = Q.front();Q.pop();
Edge e = E[now];
if(e.v == eid && e.e <= etm) return now;
for(int i = fir[e.v]; ~i; i = nxt[i])
{
if(E[i].b < e.e)
{
fir[e.v] = i;///每次修改邻接表的初始指针位置,因为走过的路就完全没必要再走一遍了。
break; /// 因为是有序的,所以可以直接跳出。
}
if(vis[i]) continue;
E[i].fa = now;
if(E[i].v == eid && E[i].e <= etm) return i;
vis[i] = true;
Q.push(i);
}
}
return -1;
}
int main()
{
// freopen("in.txt", "r", stdin);
while(scanf("%d%d", &n, &m) != EOF)
{
tot = 1;memset(fir, -1, sizeof fir);
for(int i = 1; i <= m; i ++)
{
int u, v, b, e;
scanf("%d%d%d%d", &u, &v, &b, &e);
E[i].u = u; E[i].v = v;E[i].b = b;
E[i].e = e;E[i].fa = 0;E[i].id = i;
}
sort(E + 1, E + m + 1);
for(int i = 1; i <= m; i ++)
{
AddEdge(E[i].u, E[i].v);
}
scanf("%d%d%d%d", &sid, &eid, &stm, &etm);
if(sid == eid && stm <= etm)
{
puts("0");
continue;
}
int ans = bfs();
if(ans == -1)
{
puts("Impossible");
}
else
{
vector<int> pt;
while(ans)
{
pt.push_back(E[ans].id);
ans = E[ans].fa;
}
printf("%d\n", pt.size());
for(int i = pt.size() - 1; i >= 0; i --)
{
printf("%d%c", pt[i], i == 0 ? '\n' : ' ');
}
}
}
}