牛客网暑期ACM多校训练营(第六场
F Squirtle
理解题意之后就十分好做了,唯一要注意的是会爆longlong,所以要用大数。
具体树dp见代码。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
struct BigInt
{
static const int BASE = 100000000; //基数
static const int WIDTH = 8; //基宽
vector<int> s; //存储
//构造函数 -- 使用LL
BigInt(long long num = 0)
{
*this = num;
}
//赋值运算符 -- 使用LL
BigInt operator = (long long num)
{
s.clear();
do
{
s.push_back(num % BASE);
num /= BASE;
}
while(num > 0);
return *this;
}
//赋值运算符 -- 使用string
BigInt operator = (const string& str)
{
s.clear();
int x, len = (str.length() - 1) / WIDTH + 1;
for(int i = 0; i < len; i++)
{
int end = str.length() - i*WIDTH;
int start = max(0, end - WIDTH);
sscanf(str.substr(start, end-start).c_str(), "%d", &x);
s.push_back(x);
}
return *this;
}
//比较运算符
bool operator < (const BigInt& b) const
{
if(s.size() != b.s.size()) return s.size() < b.s.size();
for(int i = s.size()-1; i >= 0; i--)
if(s[i] != b.s[i]) return s[i] < b.s[i];
return false; //相等
}
bool operator > (const BigInt& b) const
{
return b < *this;
}
bool operator <= (const BigInt& b) const
{
return !(b < *this);
}
bool operator >= (const BigInt& b) const
{
return !(*this < b);
}
bool operator != (const BigInt& b) const
{
return b < *this || *this < b;
}
bool operator == (const BigInt& b) const
{
return !(b < *this) && !(*this < b);
}
//重载输入输出
friend ostream& operator << (ostream &out, const BigInt& x)
{
out << x.s.back();
for(int i = x.s.size()-2; i >= 0; i--)
{
char buf[20];
sprintf(buf, "%08d", x.s[i]);
for(int j = 0; j < strlen(buf); j++) out << buf[j];
}
return out;
}
friend istream& operator >> (istream &in, BigInt& x)
{
string s;
if(!(in >> s)) return in;
x = s;
return in;
}
//加法
BigInt operator + (const BigInt& b) const
{
BigInt c;
c.s.clear();
for(int i = 0, g = 0; ; i++)
{
if(g == 0 && i >= s.size() && i >= b.s.size()) break;
int x = g;
if(i < s.size()) x += s[i];
if(i < b.s.size()) x += b.s[i];
c.s.push_back(x % BASE);
g = x / BASE;
}
return c;
}
//加等于
BigInt operator += (const BigInt& b)
{
*this = *this + b;
return *this;
}
//减法 -- 大减小 -- 其他的在外部处理
BigInt operator - (const BigInt& b) const
{
BigInt c;
c.s.clear();
if((*this) == b) return c = 0;
for(int i = 0, g = 0; ; ++i)
{
if(g == 0 && i >= s.size() && i >= b.s.size()) break;
int x = -g;
g = 0;
if(i < s.size()) x += s[i];
if(i < b.s.size()) x -= b.s[i];
if(x < 0) x += BASE, ++g;
c.s.push_back(x);
}
for(int i = c.s.size()-1; i >= 0 && c.s[i] == 0; --i) c.s.pop_back();
return c;
}
//乘法 -- 未使用FFT
BigInt operator * (const BigInt& b) const
{
int s1 = s.size(), s2 = b.s.size();
vector<LL> v(s1+s2+1,0);
BigInt c;
c.s.resize(s1+s2, 0);
for(int i = 0; i < s1; ++i) //相乘
for(int j = 0; j < s2; ++j)
{
v[i+j] += (LL)s[i]*b.s[j];
}
for(int i = 0; i < s1+s2; ++i) //进位
{
v[i+1] += v[i]/BASE;
v[i] %= BASE;
c.s[i] = v[i];
}
for(int i = c.s.size()-1; i >= 0 && c.s[i] == 0; --i) c.s.pop_back();
return c;
}
//除法 -- 二分
BigInt operator / (const BigInt& b) const
{
int s1 = s.size(), s2 = b.s.size();
int len = s1-s2;
BigInt c, x = *this, y = b;
if(len < 0) return c = 0;
c.s.resize(len+1, 0);
for(int i = len; i >= 0; --i)
{
//先将除数对齐
y.s.resize(s2+i,0);
for(int j = s2+i-1; j >= 0; --j)
{
if(j >= i) y.s[j] = b.s[j-i];
else y.s[j] = 0;
}
//再二分找商
int L = 0, R = BASE;
BigInt t;
while(L < R)
{
int mid = (L+R)>>1;
t = mid;
if(t*y > x) R = mid;
else L = mid+1;
}
c.s[i] = L-1;
//更新被除数
t = L-1;
x = x - t*y;
}
for(int i = c.s.size()-1; i >= 0 && c.s[i] == 0; --i) c.s.pop_back();
return c;
}
//取模
BigInt operator % (const BigInt& b) const
{
return (*this) - (*this)/b * b;
}
//开方 -- 二分 -- 浮点数可放大1e4精确一位
BigInt Sqrt()
{
BigInt L = 1, R = *this;
while(L < R)
{
BigInt mid = (L+R)/2;
if(mid*mid > *this) R = mid;
else L = mid+1;
}
return L-1;
}
};
const int maxn=2005;
vector<int>V[2*maxn+100];
char s[maxn][20];
BigInt dp[2*maxn+100][3];
BigInt tab[maxn];
int sze[2*maxn+100];
void dfs(int u)
{
sze[u]=V[u].empty();
if(V[u].empty())
{
dp[u][0]=dp[u][1]=1;
return;
}
dfs(V[u][0]);
sze[u]+=sze[V[u][0]];
dfs(V[u][1]);
sze[u]+=sze[V[u][1]];
BigInt x[2],y[2];
for(int j=0; j<2; j++)
{
if(j==0)
{
x[0]=dp[V[u][0]][0];
x[1]=tab[sze[V[u][0]]]-x[0];
}
else
{
x[1]=dp[V[u][0]][1];
x[0]=tab[sze[V[u][0]]]-x[1];
}
for(int k=0; k<2; k++)
{
if(k==0)
{
y[0]=dp[V[u][1]][0];
y[1]=tab[sze[V[u][1]]]-y[0];
}
else
{
y[1]=dp[V[u][1]][1];
y[0]=tab[sze[V[u][1]]]-y[1];
}
BigInt res[5];
for(int t=0; t<4; t++)
res[t]=x[(t>>1)&1]*y[t&1];
for(int i=0; i<16; i++)if(s[u][i]=='1')
{
BigInt tmp[2];
tmp[0]=tmp[1]=0;
for(int t=0; t<4; t++)
{
auto &thenum=tmp[(i>>t)&1];
thenum=thenum+res[t];
}
for(int t=0; t<2; t++)
{
if(dp[u][t]<tmp[t])
dp[u][t]=tmp[t];
}
}
}
}
}
void init()
{
tab[0]=1;
for(int i=1; i<maxn; i++)
tab[i]=tab[i-1]+tab[i-1];
}
int main()
{
init();
int T;
scanf("%d",&T);
int cas=1;
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1; i<=n-1; i++)
scanf("%s",s[i]);
for(int i=1; i<=2*n-1; i++)V[i].clear(),dp[i][0]=dp[i][1]=0;
int fa;
for(int i=2; i<=2*n-1; i++)
{
scanf("%d",&fa);
V[fa].push_back(i);
}
printf("Case #%d: ",cas++);
dfs(1);
cout<<dp[1][1]<<endl;
}
return 0;
}
G Pikachu
思路参考自小机灵鬼葫芦娃。
NJU-calabash_boy 2018/8/5 22:57:16
就是你考虑最大流等于最小割对吧
大学要有梦想 2018/8/5 22:57:19
dei
NJU-calabash_boy 2018/8/5 22:57:26
然后起点是u
NJU-calabash_boy 2018/8/5 22:57:32
终点是v
大学要有梦想 2018/8/5 22:57:47
恩。。
NJU-calabash_boy 2018/8/5 22:57:51
你猜一个可能是最小割的东西……
NJU-calabash_boy 2018/8/5 22:58:03
比如你把u出来的所有边割掉
NJU-calabash_boy 2018/8/5 22:58:16
或者把v出来的所有边删掉
NJU-calabash_boy 2018/8/5 22:58:22
然后取一个小的
NJU-calabash_boy 2018/8/5 22:58:35
然后你发现样例还真tmd对了
大学要有梦想 2018/8/5 22:58:39
。。。
2018/8/5 22:58:46
NJU-calabash_boy 2018/8/5 22:58:46
然后你就是要求题解说的那个东西了
NJU-calabash_boy 2018/8/5 22:58:57
最后注意爆掉了ll
NJU-calabash_boy 2018/8/5 22:59:30
这题他既然可以做………
NJU-calabash_boy 2018/8/5 22:59:38
这个最小割一定是有结论的
NJU-calabash_boy 2018/8/5 22:59:49
要不他一脸复杂度爆炸的样子
大学要有梦想 2018/8/5 22:59:55
哈哈。。
大学要有梦想 2018/8/5 23:00:00
谢谢葫芦娃
大学要有梦想 2018/8/5 23:00:06
你怎么这么聪明?
我竟无言以对。。
所以最后就是求一个点到所有的点的距离和就行了。这个过程树dp就能完成。
最后也会爆longlong,但爆的不是很多,所以这里有个处理技巧可以将一个数拆成两个数。
细节见代码。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
typedef pair<int,int>pii;
const int maxn=1e5+5;
vector<pii>G[maxn];
ll sum[maxn];
int sz[maxn];
void dfs1(int u,int pre)
{
sz[u]=1;
for(pii x:G[u])
{
int v=x.first,w=x.second;
if(v==pre)continue;
dfs1(v,u);
sz[u]+=sz[v];
sum[u]+=sum[v]+(ll)sz[v]*w;
}
}
int n;
void dfs2(int u,int pre)
{
for(pii x:G[u])
{
int v=x.first,w=x.second;
if(v==pre)continue;
ll tmp=sum[u]-sum[v]-(ll)sz[v]*w;
sum[v]=sum[v]+tmp+(ll)(n-sz[v])*w;
dfs2(v,u);
}
}
int main()
{
int T;
scanf("%d",&T);
int cas=1;
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)G[i].clear();
int u,v,w;
for(int i=1;i<n;i++)
{
sum[i]=0;
scanf("%d %d %d",&u,&v,&w);
G[u].push_back(make_pair(v,w));
G[v].push_back(make_pair(u,w));
}
sum[n]=0;
dfs1(1,0);
dfs2(1,0);
sort(sum+1,sum+1+n);
ll ans1=0,ans2=0;
for(int i=1;i<=n;i++)
{
ans1=ans1+sum[i]*(n-i);
if(ans1>=(ll)1000000000000000000)
{
ans2+=ans1/1000000000000000000;
ans1%=1000000000000000000;
}
}
if(ans2==0)
printf("Case #%d: %llu\n",cas++,ans1);
else printf("Case #%d: %llu%llu\n",cas++,ans2,ans1);
}
return 0;
}
I Team Rocket
这题博主没有用题解的方法,自己写的比较暴力,你可以开2e5个set,对于每个set的下标对应的是每个区间的左坐标,然后将右坐标依从大到小的顺序放进set里,然后每次询问的时候跑就行了,如果一个set被全部删后,以后跑就不用跑这个了,那么你可以用并查集来稍微优化一下。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
const int mod=998244353;
set<pair<int,int>,greater<pair<int,int> >>S[maxn];
typedef pair<int,int>pii;
pii lines[maxn];
int L[maxn];
int f[maxn];
inline int find(int a)
{
return a==f[a]?a:f[a]=find(f[a]);
}
int vis[maxn];
int main()
{
int T;
scanf("%d",&T);
int cas=1;
while(T--)
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)vis[i]=0;
int l,r;
for(int i=1;i<=n;i++)
{
S[i].clear();
scanf("%d %d",&l,&r);
lines[i]=pii(l,r);
L[i]=l;
}
sort(L+1,L+1+n);
int lnum=unique(L+1,L+1+n)-L-1;
for(int i=1;i<=n;i++)
{
int idx=lower_bound(L+1,L+1+lnum,lines[i].first)-L;
S[idx].insert(pii(lines[i].second,i));
}
for(int i=1;i<=lnum+1;i++)f[i]=i;
int last=0;
printf("Case #%d:\n",cas++);
for(int t=1;t<=m;t++)
{
int y;
scanf("%d",&y);
int x=(y^last);
int idx=upper_bound(L+1,L+1+lnum,x)-L;
int begin=find(1);
long long tmp=1;
int flag=0;
for(int i=begin;i<idx;i=find(i+1))
{
auto it=S[i].begin();
for(;it!=S[i].end();)
{
if((it->first)>=x)
{
vis[it->second]=t;
tmp=tmp*(it->second)%mod;
flag++;
S[i].erase(it++);
}
else break;
}
if(it==S[i].end())
{
int fv=find(i+1);
f[i]=fv;
}
}
if(flag==0)
last=0;
else last=tmp;
printf("%d\n",flag);
}
for(int i=1;i<=n;i++)
{
if(i!=1)printf(" ");
printf("%d",vis[i]);
}
puts("");
}
return 0;
}
J Heritage of skywalkert
这题又气死我了,全场都会就我不会。。
细节看题解就完事了。
#include<bits/stdc++.h>
using namespace std;
unsigned x,y,z;
const int maxn=1e7+5;
unsigned a[maxn];
unsigned tang()
{
unsigned t;
x^=x<<16;
x^=x>>5;
x^=x<<1;
t=x;
x=y;
y=z;
z=t^x^y;
return z;
}
long long gcd(long long a,long long b)
{
return b==0?a:gcd(b,a%b);
}
int main()
{
int T;
scanf("%d",&T);
int cas=1;
while(T--)
{
int n;
cin>>n>>x>>y>>z;
for(int i=1;i<=n;i++)
a[i]=tang();
int themin=min(200,n);
nth_element(a+1,a+themin,a+1+n,greater<unsigned>());
unsigned long long ans=0;
for(int i=1;i<=themin;i++)
for(int j=1;j<=themin;j++)
{
long long tmp=gcd(a[i],a[j]);
ans=max(ans,(unsigned long long)a[i]*a[j]/tmp);
}
printf("Case #%d: %llu\n",cas++,ans);
}
return 0;
}
上一篇: 关于项目SSH 框架的一点想法
推荐阅读
-
2019牛客暑期多校训练营(第二场)H Second Large Rectangle
-
2020牛客暑期多校训练营(第四场)——Basic Gcd Problem
-
2020牛客暑期多校训练营(第五场)
-
2020牛客暑期多校训练营(第九场) The Flee Plan of Groundhog
-
2020牛客暑期多校训练营Groundhog and Apple Tree(树形dp,贪心)
-
2020暑期牛客多校训练营第九场(K)The Flee Plan of Groundhog(lca,树形dp)
-
2020牛客暑期多校训练营(第二场)Cover the Tree
-
2020牛客暑期多校训练营(第一场)H-Minimum-cost Flow
-
2020牛客暑期多校 第一场 F Infinite String Comparision(字符串)
-
Harmony Pairs 2020牛客暑期多校训练营(第六场)