记得这场比赛3题出线,是我打的第一次regional,悲剧只出1题,RP掉光。
Alice and Bob
这题是矩形覆盖矩形的问题,看懂题目后就应该反映过来,此题类似LIS。
n=10w,N^2的LIS显然不行,需要NlogN的方程。
要转化为1维的LIS,此题就必须先对给定的矩形按x排序,然后再转化为y上的LIS。算是一个二次排序吧,题目和2009的waterloo某题超像,只是当时不知道。。
注意矩形是二维的,要分清何时更新LIS的答案数组。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <set>
using namespace std;
#define NN 101000
struct ret{
int h,w,pre;
bool isok(const ret &b){
if (h>b.h || ( h==b.h && w>=b.w) )
return true;
else return false;
}
bool operator < (const ret & b){
if (h<b.h || ( h==b.h && w<b.w) )
return true;
else return false;
}
};
ret a[NN],b[NN];
inline bool cmp(const ret&a, const ret&b){
if (a.h<b.h || ( a.h==b.h && a.w<b.w) )
return true;
else return false;
}
int main(){
int T,i,j,k,n,sum,bl,br,bmid;
scanf("%d",&T);
multiset<int> s;
multiset<int>::iterator it;
while (T--){
sum=0;
s.clear();
scanf("%d",&n);
for (i=0;i<n;i++)
scanf("%d %d",&a[i].h,&a[i].w);
for (i=0;i<n;i++)
scanf("%d %d",&b[i].h,&b[i].w);
sort(a,a+n,cmp);
sort(b,b+n,cmp);
for (i=0,j=0; i<n; i++){
while (j<n && b[j].h<=a[i].h){
s.insert(b[j].w);
j++;
}
if (s.empty()) continue;
it=s.upper_bound(a[i].w);
if (it==s.begin()) continue;
it--;
s.erase(it),sum++;
}
printf("%d\n",sum);
}
return 0;
}
A Simple Problem with Integers
哈哈,模板题有木有。
突破口在k<=10。开55个树状数组,记录所有数mod k的可能,然后就变成了区间和问题了。求和的时候再从k=1->10的和加起来,就OK了。
注意分组的时候用/k 不要得到0这个起点,或者你的BIT单独考虑了0这个点。
还有超内存的情况⊙﹏⊙,还是初始化的使用new一下吧,静态分配内存似乎要到32M,但是k越大,n/k越小,new一下慢不了多少,内存才6m。
#include <stdio.h>
#include <string.h>
#define N 50005
#define lowbit(i) ( i & (-i) )
//#define _clr(x) memset(x,0,sizeof(x))
typedef int typev;
struct BIT{
/* 设delta[i]表示[i,n]的公共增量 */
typev *c1; /* 维护delta[i]的前缀和 */
typev *c2; /* 维护delta[i]*i的前缀和 */
typev *Sum;
int n;
BIT (){c1=c2=Sum=0;}
void _clr(typev* &ar){
if (ar) delete []ar;
ar=new typev [n+10];
memset(ar,0,sizeof(typev)*(n+10));
}
void init(int _n){
n=_n;
_clr(c1);
_clr(c2);
_clr(Sum);
}
typev query(typev *array, int i)
{
typev ret=0;
while (i > 0) {
ret += array[i];
i -= lowbit(i);
}
return ret;
}
void update(typev *array, int i, typev d){
while (i <= n) {
array[i] += d;
i += lowbit(i);
}
}
void add(int s, int t, typev d)//将区间[s,t]所有元素加上d
{
/* 把delta[i](s<=i<=t)加d,策略是
*先把[s,n]内的增量加d,再把[t+1,n]的增量减d
*/
update(c1, s, d);
update(c1, t+1, -d);
update(c2, s, d*s);
update(c2, t+1, -d*(t+1));
}
typev sum(int s, int t)//询问区间[s,t]的和
{
typev ret;
ret = Sum[t] - Sum[s-1];
ret += (t+1)*query(c1, t) - query(c2, t);
ret -= (s*query(c1, s-1) - query(c2, s-1));
return ret;
}
}pool[55];
BIT *s[11][11];
BIT *test;
int main()
{
int i, j, n, a, b, c, k, action, ans, Q, cnt=0, len;
while ( ~scanf("%d",&n) )
{
//for (i=0; i<55; i++)
//pool[i].init(n+4);
for (i=1,cnt=0; i<=10; i++)
{
for (j=0; j<i; j++){
s[j][i]=pool+cnt++;
s[j][i]->init(n/i+10);
}
}
for (i=1; i<=n; i++)
{
scanf("%d",&a);
s[0][1]->add(i+1,i+1,a);
}
scanf("%d",&Q);
while (Q--){
scanf("%d",&action);
if (action==2)
{
scanf("%d",&a);
ans=0;
for (i=1; i<=10; i++)
ans+=s[a%i][i]->sum(a/i+1,a/i+1);
printf("%d\n",ans);
}
else{
scanf("%d %d %d %d",&a ,&b, &k, &c);
len=(b-a)/k;
s[a%k][k]->add(a/k+1,a/k+len+1,c);
}
}
}
return 0;
}
LianLianKan
这个是状压DP,据说贪心可以过。我dfs的时候用hash乱搞过掉。数据蛮水我会乱说?
#include <stdio.h>
#include <map>
#include <string.h>
#include <time.h>
using namespace std;
#define NN 1020
#define KK 2587219
clock_t tb,te;
int s[NN],dp[NN];
int hash[KK];
int fun(int n){
if (n==-1) return 1;
int tmp=0;
bool b=0;
// if (clock()-tb>1e7) return 0;
for (int i=1;i<=5;i++){
if (n-i<0) break;
if (s[n]==s[n-i]){
for (int j=n-i; j<=n-2; j++)
s[j]=s[j+1];
if (n-i-1>=0) tmp=dp[n-i-1];else tmp=0;
for (int k=n-i; k<=n-2; k++){
tmp=(tmp+s[k]%KK*(k+2))%KK;
}
//b=b||fun(n-2);
if (hash[tmp]==0) b=b||fun(n-2);
else b=b||(hash[tmp]==-1?0:1);
for (int j=n-1; j>=n-i+1; j--)
s[j]=s[j-1];
s[n-i]=s[n];
if ( b==1 ) {
hash[tmp]=1;
return 1;
}else hash[tmp]=-1;
}
}
hash[dp[n]]=-1;
return 0;
}
int main(){
int T,n,i,j,k;
while (scanf("%d",&n)!=EOF){
// tb=clock();
memset(dp,0,sizeof(dp) );
memset(hash,0,sizeof(hash) );
for (i=0;i<n;i++){
scanf("%d",&s[i]);
if (i>0) dp[i]=(dp[i-1]+s[i]%KK*(i+2) )%KK;
else dp[0]=s[i]%KK*(i+2);
}
//printf("hash=%d\n",dp[2]);
if (n%2==1) {
printf("0\n");
continue;
}
printf("%d\n",fun(n-1) );
}
return 0;
}
USACO ORZ
这个真心ORZ了,不就是dfs之后hash么?随便算算搜索树也就1000w个叶子,怎么就无限tle。hash函数太烂,没去查冲突还wa了。
还是老老实实剪枝+hash吧,居然过了。
#include <cstdio>
#include <string.h>
#include <set>
//#include <map>
using namespace std;
//typedef int ll;
set<int> s;
//bool hash[(1<<24)+5];
int mod=0x00ffffff;
inline void adjust(int &a, int &b, int &c)
{
int t;
if (a<b){
if (c<a) t=a,a=c,c=t;
if (c<b) t=b,b=c,c=t;
}else{
if (b<c) t=a,a=b,b=t;else t=a,a=c,c=t;
if (b<c) return;
else t=b,b=c,c=t;
}
}
int group[16],a[16],ans,n,len[4],tot;
bool cut(){
int a=len[1],b=len[2],c=len[3],d=tot;
adjust(a,b,c);
if (a+b+d<=c) return false;
//printf("%d %d %d %d\n",a,b,c,d);
return false;
}
void dfs(int deep){
if (deep>=n){
{
int a=len[1],b=len[2],c=len[3];
//printf("%d %d %d\n",a,b,c);
adjust(a,b,c);
if (a==0 || a+b<=c) return ;
int d;
d=((a)*10009 + b);
if (s.find(d)==s.end()){
ans++;
s.insert(d);
//hash[d]=true;
//printf("a=%d b=%d c=%d deep=%d\n",a,b,c,deep);
}
}
return ;
}
int i=deep,j;
if (group[i]==-1)
for (j=1; j<4; j++){
tot-=a[i];
len[j]+=a[i];
group[i]=j;
if (!cut()) dfs(deep+1);
group[i]=-1;
len[j]-=a[i];
tot+=a[i];
}
}
int main()
{
int i,T;
scanf("%d",&T);
while ( T-- ){
memset(group,-1,sizeof(group));
memset(len,0,sizeof(len));
tot=ans=0;
//memset(hash,0,sizeof(hash));
s.clear();
scanf("%d",&n);
for (i=0; i<n; i++){
scanf("%d",&a[i]);
tot+=a[i];
}
len[1]=a[0];
group[0]=1;
tot-=a[0];
dfs(1);
tot+=a[0];
group[0]=-1;
len[1]=0;
printf("%d\n",ans);
}
return 0;
}