【前言】
自闭了,四题以后就看着排名一直往下掉。
E想了个线段树维护阶梯,没看wiki,出来才发现是公式题。
F想了个凸包,结果是个贪心。
心态炸裂(然而rk500还能涨分)
【题目】
原题地址
瞎搞。
#include
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
int a,b,c,t;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
#endif
a=read();b=read();c=read();
t=min(a+2,b+1);t=min(t,c);
if(t<0) t=0;
printf("%d\n",t+t+t-3);
return 0;
}
排序后首尾相加即可。
#include
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=1005;
int n;
pii a[N],b[N];
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n;++i) a[i].fi=read(),a[i].se=read();
for(int i=1;i<=n;++i) b[i].fi=read(),b[i].se=read();
sort(a+1,a+n+1);sort(b+1,b+n+1);
printf("%d %d\n",a[1].fi+b[n].fi,a[1].se+b[n].se);
return 0;
}
枚举 n n n的所有约数,等差数列求和后去重即可。
#include
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=1e6+10;
int n,cnt;
ll a[N];
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
#endif
n=read();
for(int i=1,j;(ll)i*i<=n;++i)
{
if(n%i) continue;
a[++cnt]=(ll)(1+n-i+1)*(n/i)/2;
if(i*i!=n) j=n/i,a[++cnt]=(ll)(1+n-j+1)*(n/j)/2;
}
sort(a+1,a+cnt+1);
for(int i=1;i<=cnt;++i) if(a[i]!=a[i-1]) printf("%lld ",a[i]);
return 0;
}
考虑枚举将去掉多长的前缀后后面的排列恰好补充前面的,则答案是 n ⋅ n ! − ∑ k = 1 n − 1 n ! k ! n \cdot n! - \sum_{k=1}^{n-1} \frac{n!}{k!} n⋅n!−∑k=1n−1k!n!
#include
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,mod=998244353;
const int N=1e6+10;
ll n,ans,fac[N];
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
#endif
n=read();
fac[0]=1;for(int i=1;i<=n;++i) fac[i]=(ll)fac[i-1]*i%mod;
ll t=1;
for(int i=1;i<n;++i)
{
t=t*(n-i+1)%mod;
ans=(ans+(ll)t*(fac[n-i]-1)%mod)%mod;
}
ans=(ans+fac[n])%mod;
printf("%lld\n",(ans%mod+mod)%mod);
return 0;
}
Erdős–Gallai theorem
结论是对于一个从大到小排序后的度数序列 d d d,能构成简单图当且仅当:
∑ i = 1 k d i ≤ ( k ( k − 1 ) + ∑ j = k + 1 n min ( d j + k ) ) \sum_{i=1}^k d_i\leq (k(k-1)+\sum_{j=k+1}^n \min(d_j+k)) ∑i=1kdi≤(k(k−1)+∑j=k+1nmin(dj+k))对于 1 ≤ k ≤ n 1\leq k\leq n 1≤k≤n均成立。
答案显然是一个公差为 2 2 2的等差序列,我们二分答案的上下界,上述式子不成立时,若第 n + 1 n+1 n+1个点已满足条件,说明答案太大,否则说明答案太小。
#include
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=1e6+10;
int n;
ll a[N],b[N],s[N];
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
void solve()
{
n=read();
for(int i=1;i<=n;++i) a[i]=read();
sort(a+1,a+n+1);
for(int i=1;i<=n;++i) s[i]=s[i-1]+a[i];
for(int i=1,j=1;i<=n;++i)
{
ll l=s[n]-s[n-i],r=(ll)i*(i-1);
while(j<=n && a[j]<i) ++j;
r+=s[min(j-1,n-i)]+(ll)max(0,n-i-j+1)*i;
ll now=a[n-i+1],tmp=l-r;
if(tmp<=i && tmp<=now) ++b[max(tmp,0ll)],--b[now+1];
l-=a[n-i+1];r+=min(a[n-i+1],(ll)i);
tmp=r-l;
if(tmp>=now+1) ++b[now+1],--b[min(tmp+1,(ll)n+1)];
}
}
void printans()
{
ll sum=0,hv=0;
for(int i=0;i<=n;++i)
{
sum+=b[i];
if(sum==n && s[n]%2==i%2) ++hv,printf("%d ",i);
}
if(!hv) puts("-1");
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("E.in","r",stdin);
freopen("E.out","w",stdout);
#endif
solve();
printans();
return 0;
}
考虑这样一个贪心:如果我们没有体力,我们可以通过往回游半米再游回去补充体力,而这可以在第一个水中进行。如果第一个岩浆之前没有水,就在草地上走路。此外,如果有未用的体力,应当将之前一些动作转化为飞,显然应更多转化走路。
那么我们到每个格子先将可行的所有走路和游泳距离计算出。假设我们整个过程都是飞行的,那么我们需要足够体力,于是我们贪心地将一些飞行用游泳和走路来代替。如果到了某个格子发现体力无论如何都不够而不能飞了,我们再来回游泳转化为飞行即可。
#include
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=1e5+10;
int n;
ll ans,G,W,l[N];
char s[N];
ll read()
{
ll ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("F.in","r",stdin);
freopen("F.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n;++i) l[i]=read()*2,ans+=l[i];
scanf("%s",s+1);
for(int i=1,tim=5;i<=n;++i)
{
if(s[i]=='G') G+=l[i];
else if(s[i]=='W') W+=l[i],tim=3;
ll res=l[i],t;
t=min(res/2,W);ans+=t*2;res-=t*2;W-=t;
t=min(res/2,G);ans+=t*4;res-=t*2;G-=t;
ans+=res*tim;
}
printf("%lld\n",ans/2);
return 0;
}
官方题解
太长了看不懂。
然后,论python的优越性。
这是别人的c++
#include
#define ll long long
#define ull unsigned ll
#define uint unsigned
#define db long double
#define pii pair
#define pll pair
#define IT iterator
#define PB push_back
#define MK make_pair
#define LB lower_bound
#define UB upper_bound
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define UPD(x,y) (((x)+=(y))>=mo?x-=mo:233)
#define CLR(a,v) memset(a,v,sizeof(a));
#define CPY(a,b) memcpy(a,b,sizeof(a));
using namespace std;
const int LEN=80;
const int YW=8;
const int BAS=100000000;
struct big{
int a[LEN];
//delete .a[]
int& operator [](int x){
return a[x];
}
const int& operator [](int x)const{
return a[x];
}
//getnum
big(){
CLR(a,0);
}
big operator =(const big &x){
For(i,x[0]+1,a[0]) a[i]=0;
For(i,0,x[0]) a[i]=x[i];
return *this;
}
big operator =(int x){
Rep(i,a[0],0) a[i]=0;
for (;x;x/=BAS)
a[++a[0]]=x%BAS;
return *this;
}
big(int x){
CLR(a,0);
*this=x;
}
//compare
bool operator <(const big &b)const{
if (a[0]!=b[0]) return a[0]<b[0];
Rep(i,a[0],1) if (a[i]!=b[i]) return a[i]<b[i];
return 0;
}
bool operator >(const big &b)const{
if (a[0]!=b[0]) return a[0]>b[0];
Rep(i,a[0],1) if (a[i]!=b[i]) return a[i]>b[i];
return 0;
}
bool operator <=(const big &b)const{
return !(*this>b);
}
bool operator >=(const big &b)const{
return !(*this<b);
}
bool operator ==(const big &b)const{
return !(*this>b)&&!(*this<b);
}
bool operator !=(const big &b)const{
return !(*this==b);
}
//cheng
big operator *(const big &b)const{
big c; c[0]=a[0]+b[0];
For(i,1,a[0]) For(j,1,b[0]){
ll x=c[i+j-1]+1ll*a[i]*b[j];
c[i+j]+=x/BAS; c[i+j-1]=x%BAS;
}
for (;c[0]>0&&!c[c[0]];c[0]--);
return c;
}
big operator *(int x)const{
big c; ll v=0;
For(i,1,a[0]+3){
v=1ll*x*a[i]+v;
c[i]=v%BAS; v/=BAS;
}
c[0]=a[0]+3;
for (;c[0]>0&&!c[c[0]];c[0]--);
return c;
}
//chu
big operator /(int x)const{
big c; ll v=0;
Rep(i,a[0],1){
v=v*BAS+a[i];
c[i]=v/x; v%=x;
}
c[0]=a[0];
for (;c[0]>0&&!c[c[0]];c[0]--);
return c;
}
big operator /(const big &b)const{
if (b[0]==1&&!b[1]){
puts("error! divide by 0");
exit(0);
}
if (*this<b) return big(0);
int l1=max(0,(a[0]-1))*YW;
int l2=max(0,(b[0]-1))*YW;
int v1=a[a[0]],v2=b[b[0]];
for (;v1;v1/=10,l1++);
for (;v2;v2/=10,l2++);
big c,chu=*this,B=b;
For(i,1,(l1-l2)/YW) B*=BAS;
For(i,1,(l1-l2)%YW) B*=10;
Rep(i,l1-l2,0){
int x=0;
for (;chu>=B;chu-=B,x++);
c[i/YW+1]=c[i/YW+1]*10+x;
B/=10;
}
c[0]=(l1-l2)/YW+1;
for (;c[0]>0&&!c[c[0]];c[0]--);
return c;
}
//jia
big operator +(const big &b)const{
big c; c[0]=max(a[0],b[0]);
For(i,1,c[0]) c[i]=a[i]+b[i];
For(i,1,c[0]) c[i+1]+=c[i]/BAS,c[i]%=BAS;
if (c[c[0]+1]) c[0]++;
return c;
}
big operator +(int x)const{
big c=*this; c[1]+=x;
For(i,1,c[0]+1)
if (c[i]>=BAS){
c[i+1]+=c[i]/BAS;
c[i]%=BAS;
}
else break;
if (c[c[0]+1]) c[0]++;
return c;
}
//jian
big operator -(const big &b)const{
big c; c[0]=a[0];
For(i,1,c[0]) c[i]=a[i]-b[i];
For(i,1,c[0]) if (c[i]<0)
c[i]+=BAS,c[i+1]--;
for (;c[0]>1&&!c[c[0]];c[0]--);
return c;
}
big operator -(int x)const{
big c=*this; c[1]-=x;
For(i,1,c[0]+1)
if (c[i]<0){
c[i+1]+=(c[i]+1)/BAS-1;
c[i]=(c[i]+1)%BAS+BAS-1;
}
else break;
for (;c[0]>1&&!c[c[0]];c[0]--);
return c;
}
//mod
int operator %(int x)const{
ll ans=0;
Rep(i,a[0],1)
ans=(ans*BAS+a[i])%x;
return ans;
}
big operator %(const big &b)const{
if (b[0]==1&&!b[1]){
puts("error! mod by 0");
exit(0);
}
if (*this<b) return *this;
int l1=max(0,(a[0]-1))*YW;
int l2=max(0,(b[0]-1))*YW;
int v1=a[a[0]],v2=b[b[0]];
for (;v1;v1/=10,l1++);
for (;v2;v2/=10,l2++);
big chu=*this,B=b;
For(i,1,(l1-l2)/YW) B*=BAS;
For(i,1,(l1-l2)%YW) B*=10;
Rep(i,l1-l2,0){
for (;chu>=B;chu-=B);
B/=10;
}
return chu;
}
//suoxie
big operator +=(const big &b){
return *this=(*this+b);
}
big operator -=(const big &b){
return *this=(*this-b);
}
big operator *=(const big &b){
return *this=(*this*b);
}
big operator /=(const big &b){
return *this=(*this/b);
}
big operator %=(const big &b){
return *this=(*this%b);
}
big operator +=(int x){
return *this=(*this+x);
}
big operator -=(int x){
return *this=(*this-x);
}
big operator *=(int x){
return *this=(*this*x);
}
big operator /=(int x){
return *this=(*this/x);
}
//IO
void read(){
char c[LEN*YW+10];
scanf("%s",c);
int len=strlen(c);
CLR((*this).a,0);
reverse(c,c+len);
a[0]=(len-1)/YW+1;
Rep(i,len-1,0)
a[i/YW+1]=a[i/YW+1]*10+c[i]-'0';
}
void write()const{
printf("%d",a[a[0]]);
Rep(i,a[0]-1,1) printf("%08d",a[i]);
}
void writeln()const{
write(); puts("");
}
};
big gcd(const big &a,const big &b){
big A=a,B=b,ans=1;
for (;!(A[1]&1)&&!(B[1]&1);A/=2,B/=2,ans*=2);
for (;;){
if (A[0]==1&&A[1]==0) return B*ans;
if (B[0]==1&&B[1]==0) return A*ans;
for (;!(A[1]&1);A/=2);
for (;!(B[1]&1);B/=2);
A>B?A-=B:B-=A;
}
}
big q[233];
big ans[233];
int tp,tot;
int rnd(int md){
int x=0;
For(i,1,100) x=(x*10ll+rand()%10)%md;
return x;
}
big make(big n){
big x; x=n;
x[x[0]]=rnd(x[x[0]]);
For(j,1,x[0]-1) x[j]=rnd(BAS);
for (;x[0]>1&&!x[x[0]];x[0]--);
if (x[0]==1&&!x[1]) x[1]++;
return x;
}
void insert(const big &a){
//printf("insert "); a.writeln();
int pos=++tp; q[tp]=a;
Rep(i,pos-1,1){
big G=gcd(q[i],q[pos]);
if (G==1) continue;
q[i]/=G; q[pos]/=G; q[++tp]=G;
}
pos=0;
For(i,1,tp)
if (q[i]!=1)
q[++pos]=q[i];
tp=pos;
//printf("%d\n",pos);
//For(i,1,tp)
// q[i].writeln();
}
int main(){
srand(time(NULL));
big n; n.read();
q[++tp]=n;
For(i,1,10){
big x=make(n);
for (;gcd(x,n)!=1;){
insert(gcd(x,n));
x=make(n);
}
big y=x*x%n;
printf("sqrt ");
y.writeln();
fflush(stdout);
big z; z.read();
if (z!=x&&z!=n-x){
big v1=(x+z)%n;
insert(gcd(n,v1));
}
}
printf("! %d ",tp);
for (int i=1;i<=tp;i++)
q[i].write(),putchar(' ');
}
/*
1:1,20,8,13
4:2,19,5,16
7:7,14
9:3,18
15:6,15
16:4,17,10,11
18:9,12
if (gcd(i,v[i])==1) continue;
else{
erase(v[i]);
push(v[i]/G,i/G,G)
}
*/
这是别人的python
import random
import sys
def gcd(x, y):
while y:
t = x % y
x = y
y = t
return x
n = int(raw_input())
candidates = []
factors = []
for i in range(30):
x = random.randint(1, n - 1)
y = x * x % n
print "sqrt " + str(y)
sys.stdout.flush()
y = int(raw_input())
if x != y:
if x > y:
x, y = y, x
candidates.append(y - x)
def divide(n):
for d in candidates:
g = gcd(n, d)
if g != 1 and g != n:
divide(g)
divide(n / g)
return
factors.append(n)
divide(n)
answer = "! " + str(len(factors))
for x in factors:
answer += " " + str(x)
print answer
满足条件的 k k k显然我们可以用线性筛求出来。
每个游戏可以用一个二元组 ( x , y ) (x,y) (x,y)来表示差值,每次操作实际上双方都可以将 x x x或 y y y减去 k k k,这就十分对称了。接下来显然每个游戏是独立的,那么这就十分 Nim \text{Nim} Nim了,于是实际上一个二元组也可以拆成两个游戏。
现在我们有一个 SG \text{SG} SG值不超过 1 0 5 10^5 105的游戏了,我们可以暴力做到 O ( m 2 ) O(m^2) O(m2),其中 m m m是两棋子间最大距离( 2 × 1 0 5 2\times 10^5 2×105)。过不了过不了。
然后我们维护 k k k个 bitset \text{bitset} bitset,第 i i i个 bitset \text{bitset} bitset的第 j j j位为 1 1 1,当且仅当状态 j j j有 i i i这个后继状态( SG \text{SG} SG)。
然后我们维护一个所有素数和素数乘积的 bitset \text{bitset} bitset为 P P P,对于每个状态 i i i,我们给第 j j j个 bitset \text{bitset} bitset或上 P P P左移 i i i位即可。
可以(打表)证明 SG \text{SG} SG函数值最多 100 100 100,于是我们就可以玄学过了。
#include
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=2e5+10,K=100;
int n,f,pnum,ans,sg[N],pri[N],bo[N];
bitset<N>G[K],P;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
void getp()
{
for(int i=2;i<N;++i)
{
if(!bo[i]) pri[++pnum]=i,P[i]=1;
for(int j=1;j<=pnum && (ll)i*pri[j]<N;++j)
{
bo[i*pri[j]]=1;
if(!bo[i]) P[i*pri[j]]=1;
if(!(i%pri[j])) break;
}
}
}
void solve()
{
n=read();f=read();P[f]=0;
sg[0]=sg[1]=0;G[0]|=P|(P<<1);
for(int i=2;i<N;++i)
{
while(G[sg[i]][i]) ++sg[i];
G[sg[i]]|=P<<i;
}
for(int i=1;i<=n;++i)
{
int a=read(),b=read(),c=read();
ans^=sg[b-a-1]^sg[c-b-1];
}
if(ans) puts("Alice\nBob");
else puts("Bob\nAlice");
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("H.in","r",stdin);
freopen("H.out","w",stdout);
#endif
getp();solve();
return 0;
}
【总结】
HELLO 2019 见。