T1 并王(bing)
Sol
卡常臭题。但是关我一个考场写\(O(n^3)\)暴力什么事呢?
好像可以优化到\(\sum_{i=1}^n f(n)\),\(f(n)\)表示\(n\)二进制下1
的个数。但是这是基于随机数据优化。如果全部是\(2^{64}-1\)那效率甚至不如我的。
按位统计。从左往右:
如果第\(i\)个数二进制第\(j\)位是1
,那么这一位贡献就是\(\frac{(i-1)*(i-2)}{2}*(1<<j)\),表示前面随便选两个数都可以;同时\(t_j++\),表示目前有多少数第\(j\)位是1
。
如果第\(i\)个数二进制第\(j\)位是0
,那么这一位贡献就是\(f_j*(i-1-f_j)*(1<<j)\),表示前面选择一个第\(j\)位是1
,一个是0
的,这样异或起来就是1
。
综上所述:开一个桶统计每一位当前1
个数,时间复杂度\(O(64*n)\),且常数非常小(当然大于\(1\))。只带O2只能1.09秒,火车头加上轻松过。
Code
#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int N=4000005;
int n, k;
int a[N], ans, U, seed;
int t[64];
signed main()
{
freopen("bing.in", "r", stdin);
freopen("bing.out", "w", stdout);
scanf("%llu%llu%llu", &n, &seed, &k);
U=(k==64?0ull:(1ull<<k))-1ull;
mt19937_64 rnd(seed);
for(int i=1; i<=n; ++i)
{
a[i]=rnd()&U;
//do sth
for(int j=63;~j;j--)
{
if((a[i]&(1ull<<j)))
{
ans+=(i-1ull)*(i-2ull)/2ull*(1ull<<j);
t[j]++;
}else ans+=t[j]*(i-1ull-t[j])*(1ull<<j);
}
}
printf("%llu\n", ans);
return 0;
}
T2、T3
都不会。不过T3的80分可以提一下。
对于80分,假设一共有\(k\)个岛屿\(x\)块陆地,先\(O(n^2)\)DFS一遍算出每个点属于的岛屿。然后\(O(x^2)\)计算一对岛屿之间的直飞距离。由于直飞距离显然\(\leq n+m\),所以设\(dp[i][j]\)表示已经过长度为\(i\),现在在\(j\)最多坐了几次飞机。那么枚举每条边即可,时间复杂度\(O(k^2n)\),虽然在最坏条件下\(subtask\ 3\;n\leq 90\)是过不了的,但是实际上数据比较水且本题1.5s开O2,所以能喜提80分。
Code
#include<bits/stdc++.h>
using namespace std;
namespace io
{
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
return f?x:-x;
}
inline void print(int x)
{
static int s[20],len;
len=0;
if(x<0)putchar('-'),x=-x;
if(x==0)
{
putchar('0');return;
}
while(x)
{
s[++len]=x%10;
x/=10;
}
for(int i=len;i;i--)putchar(s[i]+'0');
return;
}
}
using namespace io;
const int maxn=300,maxi=4510;
bool isl[maxn][maxn];
int te[maxn][maxn],dis[maxi][maxi],gpc,ans[maxi];
int lax[maxi],lay[maxi],len;
int dp[maxi][maxn<<1];
char s[maxn];
int n,m,xs,ys;
const int xx[4]={0,1,0,-1},yy[4]={1,0,-1,0};
inline bool ing(int x,int y)
{
if(x>0&&x<=n&&y>0&&y<=m)return 1;
return 0;
}
inline void dfs(int x,int y)
{
te[x][y]=gpc;
for(int i=0;i<4;i++)
{
int tox=x+xx[i],toy=y+yy[i];
if(!ing(tox,toy))continue;
if(!isl[tox][toy])continue;
if(te[tox][toy])continue;
dfs(tox,toy);
}
return;
}
struct node
{
int di,id,ti;
};
queue<node>qu;
inline void bfs(int st,int lim,int tow)
{
qu.push((node){0,st,1});ans[tow]=1;
while(!qu.empty())
{
int x=qu.front().id,v=qu.front().di,t=qu.front().ti;
qu.pop();
if(v+dis[x][tow]<=lim)ans[tow]=max(ans[tow],t);
for(int i=1;i<=gpc;i++)
{
if(i==x)continue;
if(i==tow)continue;
if(v+dis[i][x]>lim)continue;
qu.push((node){v+dis[i][x],i,t+1});
}
}
return;
}
int main()
{
freopen("island.in","r",stdin);
freopen("island.out","w",stdout);
n=read();m=read();xs=read();ys=read();
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)isl[i][j]=s[j]-'0';
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!isl[i][j])continue;
lax[++len]=i;lay[len]=j;
if(te[i][j])continue;
gpc++;
dfs(i,j);
}
}
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=len;i++)
{
dis[i][i]=0;
for(int j=i+1;j<=len;j++)
{
if(te[lax[i]][lay[i]]==te[lax[j]][lay[j]])continue;
dis[te[lax[i]][lay[i]]][te[lax[j]][lay[j]]]=min(dis[te[lax[i]][lay[i]]][te[lax[j]][lay[j]]],abs(lax[i]-lax[j])+abs(lay[i]-lay[j]));
dis[te[lax[j]][lay[j]]][te[lax[i]][lay[i]]]=min(dis[te[lax[j]][lay[j]]][te[lax[i]][lay[i]]],abs(lax[i]-lax[j])+abs(lay[i]-lay[j]));
}
}
memset(dp,-1,sizeof(dp));
dp[te[xs][ys]][0]=0;
for(int i=1;i<=n+m-2;i++)
{
for(int j=1;j<=gpc;j++)
{
for(int k=1;k<=gpc;k++)
{
if(j==k)continue;
if(dis[j][k]>i)continue;
if(dp[k][i-dis[j][k]]==-1)continue;
dp[j][i]=max(dp[j][i],dp[k][i-dis[j][k]]+1);
}
if(dis[te[xs][ys]][j]>=i)
{
ans[j]=max(ans[j],dp[j][i]);
}
}
}
ans[te[xs][ys]]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!isl[i][j])putchar('0');
else print(ans[te[i][j]]);
putchar(' ');
}putchar('\n');
}
return 0;
}
T4 玛雅历(maya)
和julian异曲同工的臭题。
最大的统计天数也不超过long long数据范围,所以先把输入转换成总计天数。然后把这个天数分段处理,我的做法分的比较细,先8月,然后-3114年,然后-3113-3101年,然后-3101-2801年,然后-2801~-1年,然后公元年以后。
每次都更新一下当前时间,注意细节即可。票池的解法是先把400年的大循环暴力预处理出来,这里时间复杂度\(O(10^5)\),很低。然后直接不断取模再寻找对应日期就可以了,注意跨年的特殊处理即可。很可惜,最后突然改题干以后票池炸了,或许慢慢来分类更稳吧。
Code(臭死了)
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace io
{
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
return f?x:-x;
}
inline void print(int x)
{
static int s[20],len;
len=0;bool flag=0;
if(x<0)flag=1,x=-x;
if(x==0)
{
putchar('0');return;
}
while(x)
{
s[++len]=x%10;
x/=10;
}
for(int i=len;i;i--)putchar(s[i]+'0');
if(flag)putchar(' '),putchar('B'),putchar('C');
return;
}
}
int T,day;
const int month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
const int moth[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
int nd,nm,ny;
inline void output()
{
using namespace io;
print(day+1);putchar(' ');print(nm);putchar(' ');print(ny);putchar('\n');return;
}
inline void sibai()
{
if(day<=36524)
{
ny+=4*(day/1461);
day%=1461;
if(day>=366)
{
day-=366;ny++;
ny+=(day/365);
day%=365;
while(day>=month[nm])
{
day-=month[nm];nm++;
}
output();return;
}else
{
while(day>=moth[nm])
{
day-=moth[nm];nm++;
}
output();return;
}
}
day-=36525;ny+=100;
ny+=100*(day/36524);
day%=36524;
if(day<=1459)
{
ny+=(day/365);
day%=365;
while(day>=month[nm])
{
day-=month[nm];nm++;
}
output();return;
}
day-=1460;ny+=4;
ny+=4*(day/1461);
day%=1461;
if(day>=366)
{
day-=366;ny++;
ny+=(day/365);
day%=365;
while(day>=month[nm])
{
day-=month[nm];nm++;
}
output();return;
}else
{
while(day>=moth[nm])
{
day-=moth[nm];nm++;
}
output();return;
}
}
signed main()
{
freopen("maya.in","r",stdin);
freopen("maya.out","w",stdout);
using namespace io;
T=read();
while(T--)
{
day=0;nd=11,nm=8,ny=-3114;
for(int i=1;i<=9;i++)day=day*(i==8?18:20)+read();
// cout<<day<<endl;
if(day<=20)
{
nd+=day;print(nd);putchar(' ');print(nm);putchar(' ');print(ny);putchar('\n');continue;
}
day-=21;nm=9;
if(day<=121)
{
while(day>=month[nm])
{
day-=month[nm],nm++;
}
output();continue;
}
day-=122;nd=1;nm=1;ny=-3113;
if(day<=4382)
{
ny+=4*(day/1461);
day%=1461;
if(day>=366)
{
day-=366;ny++;
ny+=(day/365);
day%=365;
while(day>=month[nm])
{
day-=month[nm];nm++;
}
output();continue;
}else
{
while(day>=moth[nm])
{
day-=moth[nm];nm++;
}
output();continue;
}
}
day-=4383;nm=1;ny=-3101;
if(day<=109571)
{
ny+=100*(day/36524);
day%=36524;
if(day<=1459)
{
ny+=(day/365);
day%=365;
while(day>=month[nm])
{
day-=month[nm];nm++;
}
output();continue;
}
day-=1460;ny+=4;
ny+=4*(day/1461);
day%=1461;
if(day>=366)
{
day-=366;ny++;
ny+=(day/365);
day%=365;
while(day>=month[nm])
{
day-=month[nm];nm++;
}
output();continue;
}else
{
while(day>=moth[nm])
{
day-=moth[nm];nm++;
}
output();continue;
}
}
day-=109572;nm=1;ny=-2801;
if(day<=1022678)
{
ny+=400*(day/146097);
day%=146097;
sibai();continue;
}
day-=1022679;
if(day<=366)
{
nm=1;ny=-1;
while(day>=moth[nm])
{
day-=moth[nm];nm++;
}
output();continue;
}
nm=1;ny=0;
ny+=400*(day/146097);
day%=146097;
sibai();
}
return 0;
}