WAhaha_hnu(zoj 2010 oct月試合)
15738 ワード
公式解題報告 http://blog.watashi.ws/1515/zojmonthly1010/
A題 签到问题,
View Code
B題 最初は問題の意味を間違えて理解していたので、最後まで油断していました~~
横断をx,縦断をy,クローンをaとすると,総分数n,および操作回数mに対して共有する.
2*x*(y+1) + a = n
x + y + a = m
n,mはいずれも比較的大きいが,x*y<=n=>x<=sqrt(n)‖y<=sqrt(n)
したがって,x,yが対称であるため,x,yからsqrt(n)をそれぞれ列挙することによって結果を得ることができ,1サイクルで得ることができる.
また,以上の2式の成立条件はx>0を前提としているので,x=0の場合は特判,n<=mの場合も特判とする.
View Code
E问题看题后第一眼想到DP,但时间复雑度不能接受,然后没管管了,振り返って考えてみると、贪欲は过ごすことができるはずだと思った...学べば学ぶほど愚かになった~~~
タイトルはトラップ順に限定されず、トラップをD順に並べた後、順次処理し、累積時間T<=Diであれば取り壊し、そうでなければ失血し、この場合[1,i]区間を選択する
中時間消費が最も大きく、ここでは優先キューを使用してメンテナンスします.
View Code
I題じòぴé(′▽`)∞は、試合中に問題を見る能力がまだ足りないので、問題を割引上の点が隣接する直接距離と見間違えた.
折れ線の全長を計算し、点間距離を求め、始点からシミュレーション検索を開始すると結果が得られます.
A題 签到问题,
View Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
using namespace std;
const int N = 101100;
char str[N];
bool isch( char ch ){
if( (ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z') )
return true;
return false;
}
string get_str( int x ){
string tmp;
char sa[1010];
int len = 0;
while( x ){
sa[len++] = x%10 + '0'; x /= 10;
}
for(int i = len-1; i >= 0; i-- )
tmp += sa[i];
return tmp;
}
int main(){
while( gets( str) ){
if( strcmp( str, "EOF" ) == 0 ) break;
//printf("str = %s", str );
int len = strlen(str), n = 0, i = 0;
string s;
while( i < len )
{
if( isch( str[i] ) ){
s += str[i];
int t = i+1;
while( isch(str[t]) && (t<len) ) ++t;
t--;
if( t-i >= 1 ){
if( t-i >= 2 )
s += get_str( t-i-1 );
s += str[t];
}
i = t+1;
}
else s += str[i++];
}
printf("%s
", s.c_str() );
}
return 0;
}
B題 最初は問題の意味を間違えて理解していたので、最後まで油断していました~~
横断をx,縦断をy,クローンをaとすると,総分数n,および操作回数mに対して共有する.
2*x*(y+1) + a = n
x + y + a = m
n,mはいずれも比較的大きいが,x*y<=n=>x<=sqrt(n)‖y<=sqrt(n)
したがって,x,yが対称であるため,x,yからsqrt(n)をそれぞれ列挙することによって結果を得ることができ,1サイクルで得ることができる.
また,以上の2式の成立条件はx>0を前提としているので,x=0の場合は特判,n<=mの場合も特判とする.
View Code
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MIN(a,b) (a)<(b)?(a):(b)
typedef long long LL;
int main(){
int n, m, T;
scanf("%d", &T);
while( T-- )
{
scanf("%d %d", &n,&m);
if( n <= m ){
printf("-1
");
continue;
}
if( n-1 == m ){
printf("0
");
continue;
}
bool flag = false;
int res = m+1;
int Max = sqrt(n)+1;
for(int x = 0; x <= Max; x++ )
{
int ta = n-m-x, tb = 2*x-1;
if( ta%tb == 0 ){
int y = ta/tb;
if( (y>=0) && (x+y<=m) ){
flag = true;
res = MIN( res, m-x-y );
}
}
ta = n-m+x; tb = 2*x+1;
if( ta%tb == 0 ){
int y = ta/tb;
if( (y >=0) && (x+y<=m) ){
flag = true;
res = MIN( res, m-x-y);
}
}
}
if( flag ) printf("%d
", res );
else printf("-1
");
}
return 0;
}
E问题看题后第一眼想到DP,但时间复雑度不能接受,然后没管管了,振り返って考えてみると、贪欲は过ごすことができるはずだと思った...学べば学ぶほど愚かになった~~~
タイトルはトラップ順に限定されず、トラップをD順に並べた後、順次処理し、累積時間T<=Diであれば取り壊し、そうでなければ失血し、この場合[1,i]区間を選択する
中時間消費が最も大きく、ここでは優先キューを使用してメンテナンスします.
View Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 25010;
pair<int,int> p[N];
int n, k;
int main(){
while( scanf("%d%d", &n,&k) != EOF)
{
for(int i = 0; i < n; i++)
scanf("%d%d", &p[i].second,&p[i].first );
sort( p, p+n );
int T = 0, hp = 0;
priority_queue< int > Q;
for(int i = 0; i < n; i++ ){
T += p[i].second;
Q.push( p[i].second );
while( T > p[i].first ){
T -= Q.top(); Q.pop();
hp++;
}
}
if( hp < k ) printf("%d
", hp );
else printf("-1
");
}
return 0;
}
I題じòぴé(′▽`)∞は、試合中に問題を見る能力がまだ足りないので、問題を割引上の点が隣接する直接距離と見間違えた.
折れ線の全長を計算し、点間距離を求め、始点からシミュレーション検索を開始すると結果が得られます.