A.裁纸刀(找规律)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll res=4;
int main(){
/*int n,m;
cin>>n>>m;
res+=n-1;
res+=(m-1)*n;
cout<<res;
*/
cout<<443;
return 0;
}
B.灭鼠先锋(博弈论)
注意必败态的判别条件,这里必败态是只剩一个地方没放,和放石子不同,放石子是放满了才是必败态,注意区别!!!所以这里要手动统计还剩的地方,判断是否为必败态
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
map<string,int> f;
int check(string s){
int t=0;
for(int i=0;i<8;i++){
if(s[i]=='0') t++;
}
return t;
}
int sg(string x){
if(f.count(x)) return f[x];
//x为必败态
if(check(x)==1){
f[x]=0;
return f[x];
}
set<int> st;
//放一个
for(int i=0;i<8;i++){
if(x[i]=='X') continue;
string t=x;
t[i]='X';
st.insert(sg(t));
}
//放两个
for(int i=0;i+1<=3;i++){
if(x[i]=='X'||x[i+1]=='X') continue;
string t=x;
t[i]='X';
t[i+1]='X';
st.insert(sg(t));
}
for(int i=4;i+1<=7;i++){
if(x[i]=='X'||x[i+1]=='X') continue;
string t=x;
t[i]='X';
t[i+1]='X';
st.insert(sg(t));
}
for(int i=0;;i++){
if(!st.count(i)){
f[x]=i;
break;
}
}
return f[x];
}
int main(){
/*string s[]={"X0000000","XX000000","0X000000","0XX00000"};
for(int i=0;i<4;i++){
//先手走了一步
//先手后手转换 sg=0 先手必胜
if(sg(s[i])==0) cout<<"V";
else cout<<"L";
}*/
cout<<"LLLV";
return 0;
}
C.求和(前缀和)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll res;
ll w[N];
ll sum[N];
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&w[i]);
sum[i]=sum[i-1]+w[i];
}
for(int i=1;i<=n;i++){
res+=w[i]*(sum[n]-sum[i]);
}
printf("%lld",res);
}
D.选数异或(思维)
判断[l,r]之间是否有两个数异或等于x,等价是否存在一个数t,在区间内同时存在t^x
① 用pos[i]记录i上次出现的位置
② 用left[i]记录在w[i]左侧,且与w[i]匹配的最近的数的位置
遍历[l,r],判断是否存在left[i]>=l即可(可能超时,正确做法是用线段树,维护区间内left的最大值,判断[l,r]内left最大值是否>=l)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll w[N];
int n,m;
ll x;
unordered_map<ll,int> pos;//上次出现的位置
int left_[N];//i左边最近的满足要求的数的位置
int main(){
scanf("%d%d%lld",&n,&m,&x);
for(int i=1;i<=n;i++){
scanf("%lld",&w[i]);
pos[w[i]]=i;
left_[i]=pos[w[i]^x];
}
while(m--){
int l,r;
scanf("%d%d",&l,&r);
bool f=false;
for(int i=l;i<=r;i++){
if(left_[i]>=l){
f=true;
break;
}
}
if(f) printf("yes\n");
else printf("no\n");
}
}
线段树维护
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define fast(); ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e5+5;
int n,m;
ll A[N],x;
unordered_map<ll,int> pos;//某个数上次出现的位置
int left_[N];//left_[i] 左边最近的满足的数的位置
struct node{
int l,r;
int maxn;
}tr[N<<2];
void pushup(int u){
tr[u].maxn=max(tr[u<<1].maxn,tr[u<<1|1].maxn);
}
void build(int u,int l,int r){
if(l==r){
tr[u].l=tr[u].r=l;
tr[u].maxn=left_[l];
return;
}
tr[u].l=l;
tr[u].r=r;
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
//求l,r的left[i]的最大值
int query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].maxn;
int mid=tr[u].l+tr[u].r>>1;
int maxn=0;
if(mid>=l) maxn=max(maxn,query(u<<1,l,r));
if(mid<r) maxn=max(maxn,query(u<<1|1,l,r));
return maxn;
}
int main(){
scanf("%d%d%lld",&n,&m,&x);
for(int i=1;i<=n;i++){
scanf("%d",&A[i]);
pos[A[i]]=i;
left_[i]=pos[A[i]^x];
}
build(1,1,n);
while(m--){
int l,r;
scanf("%d%d",&l,&r);
int res=query(1,l,r);
if(res>=l) printf("yes\n");
else printf("no\n");
}
}
E.爬树的甲壳虫(概率期望推导+逆元)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5,mod=998244353;
int n;
ll xx[N],yy[N];
ll qmi(ll a,ll k){
ll res=1;
while(k){
if(k&1) res=res*a%mod;
a=a*a%mod;
k>>=1;
}
return res;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>xx[i]>>yy[i];
}
ll res=0,d=1;
for(int i=n;i>=1;i--){
ll x=xx[i],y=yy[i];
d=(d*y)%mod;
d=d*qmi(y-x,mod-2)%mod;
res=(res+d)%mod;
}
cout<<res;
}
F.青蛙过河(二分)
枚举区间长度L,check为判断所有长度为L的区间和是否全不小于2x,二分枚举满足要求的最大区间长度
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,x;
int h[N];
ll sum[N];
bool check(int mid){
for(int i=1;i+mid-1<n;i++){
int j=i+mid-1;
if(sum[j]-sum[i-1]<(ll)2*x) return false;
}
return true;
}
int main(){
scanf("%d%d",&n,&x);
for(int i=1;i<n;i++){
scanf("%d",&h[i]);
sum[i]=sum[i-1]+h[i];
}
int l=0,r=n-1;
while(l<r){
int mid=l+r>>1;
if(check(mid)){
r=mid;
}else{
l=mid+1;
}
}
cout<<l<<endl;
}
G.最长不下降子序列(上升子序列+线段树)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5;
int dp1[N];//以a[i]结尾的最长不下降子序列的长度
int dp2[N];//以a[i]开头的最长不下降子序列的长度
int a[N],b[N];
int n,k;
int res,m;
struct node{
int l,r;
int maxn;
}tr[N<<2];
void pushup(int u){
tr[u].maxn=max(tr[u<<1].maxn,tr[u<<1|1].maxn);
}
void build(int u,int l,int r){
if(l==r){
tr[u]={l,r,0};
}else{
tr[u]={l,r};
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
void modify(int u,int pos,int val){
if(tr[u].l==tr[u].r) tr[u].maxn=max(tr[u].maxn,val);
else{
int mid=tr[u].l+tr[u].r>>1;
if(pos<=mid) modify(u<<1,pos,val);
else modify(u<<1|1,pos,val);
pushup(u);
}
}
int query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].maxn;
int mid=tr[u].l+tr[u].r>>1;
int maxn=-1;
if(l<=mid) maxn=max(maxn,query(u<<1,l,r));
else maxn=max(maxn,query(u<<1|1,l,r));
return maxn;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+n+1);
if(n==k){
cout<<n;
return 0;
}
m=unique(b+1,b+n+1)-(b+1);
for(int i=1;i<=n;i++){
int l=1,r=m;
while(l<r){
int mid=l+r>>1;
if(b[mid]>=a[i]) r=mid;
else l=mid+1;
}
a[i]=l;
}
build(1,1,m);
//从前往后,查在a[i]前,且比a[i]小的,dp1的最大值
for(int i=1;i<=n-k;i++){
dp1[i]=query(1,1,a[i])+1;
modify(1,a[i],dp1[i]);
}
build(1,1,m);
//从后往前,查在a[i]后,且比a[i]大的,dp2的最大值
for(int i=n;i>=k+1;i--){
res=max(res,dp1[i-k]+k+query(1,a[i-k],m));
dp2[i]=query(1,a[i],m)+1;
modify(1,a[i],dp2[i]);
}
for(int i=1;i<=n-k;i++){
res=max(res,dp1[i]+k);
}
for(int i=n;i>=k+1;i--){
res=max(res,dp2[i]+k);
}
cout<<res;
}
H.扫描游戏(几何)
根据象限和斜率,按照顺时针排序,模拟
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+5;
int res[N],idx;
struct node{
ll x,y,z;
double h;
int pos;
};
int n;
ll L;
vector<node> vc;
bool cmp(node a,node b){
if((ll)a.x*b.x<0) return a.x>b.x;
double ka,kb;
if(a.x==0){
if(a.y>=0) ka=1e9;
else ka=-1e9;
}else{
ka=a.y*1.0/a.x;
}
if(b.x==0){
if(b.y>=0) kb=1e9;
else kb=-1e9;
}else{
kb=b.y*1.0/b.x;
}
return ka>kb;
}
int main(){
scanf("%d%lld",&n,&L);
memset(res,-1,sizeof res);
for(int i=1;i<=n;i++){
ll x,y,z;scanf("%lld%lld%lld",&x,&y,&z);
node t={x,y,z,(double)sqrt(x*x*1.0+y*y*1.0),i};
vc.push_back(t);
}
int cnt=0;
do{
vector<node> ne;
sort(vc.begin(),vc.end(),cmp);
double kk=1e-18;
for(int i=0;i<vc.size();i++){
node t=vc[i];
if(t.h<=L){
double k;
if(t.x==0) k=-1e9;
else k=t.y*1.0/t.x;
if(k!=kk){
res[t.pos]=++idx;
}else{
res[t.pos]=idx++;
}
kk=k;
L+=t.z;
}else{
ne.push_back(t);
}
}
if(vc.size()==ne.size()) cnt++;
else cnt=0;
vc=ne;
}while(cnt<=2);
for(int i=1;i<=n;i++){
printf("%d",res[i]);
if(i!=n) printf(" ");
}
}
I.数的拆分(质数)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=4005;
int prime[N];
int cnt;
bool vis[N];
void init(){
for(int i=2;i<N;i++){
if(!vis[i]){
prime[++cnt]=i;
}
for(int j=1;prime[j]*i<N;j++){
vis[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
}
//判断是否是平方数/立方数
bool check(ll x){
if((ll)sqrt(x)*sqrt(x)==x) return true;
int l=1,r=2e6;
while(l<r){
int mid=l+r>>1;
if((ll)mid*mid*mid>=x) r=mid;
else l=mid+1;
}
if((ll)l*l*l==x) return true;
return false;
}
int main(){
init();
int t;cin>>t;
while(t--){
ll x;cin>>x;
if(check(x)){
cout<<"yes"<<endl;
continue;
}
bool f=true;
for(int i=1;i<=cnt;i++){
if(x%prime[i]==0){
int s=0;
while(x%prime[i]==0){
s++;
x/=prime[i];
}
if(s<2){
f=false;
break;
}
}
}
if(f&&check(x)){
cout<<"yes"<<endl;
}else{
cout<<"no"<<endl;
}
}
}
J.推导部分和(差分约束+并查集)
根据等式建立差分约束,并查集记录两点间是否有约束关系
对于一个点x,如果还未被访问过,说明发现新的约束点集合,点x是集合内编号最小的点,从点x开始bfs求的集合内点到x的距离
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5,M=N<<1;
int h[N],e[M],ne[M],idx;
ll w[M];
int p[N];
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int n,m,q;
void add(int a,int b,ll c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
ll dis[N];
bool vis[N];
void bfs(int st){
queue<int> q;
vis[st]=true;
dis[st]=0;
q.push(st);
while(!q.empty()){
int t=q.front();q.pop();
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(vis[j]) continue;
vis[j]=true;
dis[j]=dis[t]+w[i];
q.push(j);
}
}
}
int main(){
cin>>n>>m>>q;
memset(h,-1,sizeof h);
for(int i=0;i<=n;i++) p[i]=i;
for(int i=1;i<=m;i++){
int l,r;ll s;cin>>l>>r>>s;
add(l-1,r,s);
add(r,l-1,-s);
p[find(l-1)]=find(r);
}
for(int i=0;i<=n;i++){
if(!vis[i]){
bfs(i);
}
}
while(q--){
int l,r;cin>>l>>r;
if(find(l-1)!=find(r)) cout<<"UNKNOWN\n";
else{
ll res=dis[r]-dis[l-1];
cout<<res<<endl;
}
}
}