trick
priority_queue<int>que//默认最大的先出来 priority_queue<int,vector<int>,greater<int> >que;///最小的先出来
struct node{ int x,y; bool operator < (const node &b)const{ return x<b.x;///大的先出来 } }x1,x2,x3;
y=floor(x)//(向下取整) y=ceil(x)//(向上取整)
y=round(x)//四舍五入
排序部分
sort(a,a+n)///快排,不稳定 stable_sort(a,a+n)///归并排序,稳定。有时sort T了 可以用
定义n*m向量数组
int n,m; scanf("%d%d",&n,&m); vector<vector<int> >vv(n,vector<int>(m));
输出int128
#include <bits/stdc++.h> using namespace std; inline __int128 read(){ __int128 x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*f; } inline void print(__int128 x){ if(x<0){ putchar('-'); x=-x; } if(x>9) print(x/10); putchar(x%10+'0'); } int main(void){ __int128 a = read(); __int128 b = read(); __int128 m =read(); print((a + b)%m); cout<<endl; return 0; }
排序写法:
sort(a+1,a+1+n,[&](node A,node B){ return A.val>B.val; });
取模的组合数:
ll ksm(ll x,ll y,ll p){ ll res=1ll; while(y){ if(y&1) res=res*x%p; y>>=1; x=x*x%p; } return res; } struct CC{ static const int N=300010; ll fac[N],inv[N]; CC(){ fac[0]=1; for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%mod; inv[N-1]=ksm(fac[N-1],mod-2,mod); for(int i=N-1;i>=1;i--) inv[i-1]=inv[i]*i%mod; } ll operator()(ll a,ll b){ ///a>=b if(a<b || b<0)return 0; return fac[a]*inv[a-b]%mod*inv[b]%mod; } ll A(ll a,ll b){ ///a>=b if(a<b || b<0)return 0; return fac[a]*inv[a-b]%mod; } }C; int main(){ ///直接C(n,m);//n>=m }
求“短”的subsequence(非连续,不重复)在原串出现次数(含问号,全能字符),复杂度:O(nm)(https://codeforces.com/contest/1426/problem/F)
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r typedef long long ll; const int mod=1e9+7; const int M=2e6+6; const int inf=0x3f3f3f3f; const ll INF=1e18; char s[M]; ll f[10]; int main(){ int n; scanf("%d%s",&n,s+1); f[0]=1ll; f[1]=f[2]=f[3]=0; for(int i = 1; i <= n; i++){ if(s[i]=='?'){ f[3]=(f[3]*3ll+f[2])%mod; f[2]=(f[2]*3ll+f[1])%mod; f[1]=(f[1]*3ll+f[0])%mod; f[0]=(f[0]*3ll)%mod; } else f[s[i]-'a'+1] = (f[s[i]-'a'+1]+f[s[i]-'a'])%mod; } printf("%lld\n",f[3]); return 0; } /***********************求“2020”的子序列的个数***************/ /***********************二分***************/ const int N=1e5+5; int i,j,k; int n,m,t; int a[N]; int C(int aim) { int bits[5]={0}; bits[1]=aim; for(int i=1;i<=n;i++){ if(a[i]==1) continue; if(a[i]==2) { if(bits[1]) bits[1]--,bits[2]++; else if(bits[3]) bits[3]--,bits[4]++; } if(a[i]==0){ if(bits[2]) bits[2]--,bits[3]++; else if(bits[4]) bits[4]--; } } if(bits[1] || bits[2] || bits[3] || bits[4]) return 0; return 1; } int main() { //IOS; while(~sd(n)){ for(int i=1;i<=n;i++) scanf("%1d",&a[i]); int l=0,r=n/4+1,ans=0; while(r>=l){ int mid=l+r>>1; if(C(mid)) l=mid+1,ans=mid; else r=mid-1; } pd(ans); } //PAUSE; return 0; }
求1~n的前缀和的前缀和:
ans = n * n * (n + 1) / 2;///把每一个前缀和看作到n的前缀和,总共有n个; ans -= n * (n + 1) * (2 * n + 1) / 6;///列出来发现可以把上一项减去1^2+2^2+3^2+4^2……n^2=n * (n + 1) * (2 * n + 1) / 6 再加上1~n的前缀和 ans += n * (n + 1) / 2;
set去最后一个值,定义时依照制定的来排序:
///依照dfs序来排序 struct cmp{ bool operator() (const int &x,const int &y)const{ return dfn[x]<dfn[y]; } }; set<int,cmp>st[M]; /// cout<<ser.rbegin()<<endl;
vector 去重:
sort(vec.begin(), vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end()); for(int x : vec) cout << x << ",";
构建SAM:
https://yutong.site/sam/
问(长度为n)每个a数组中长度为k的子数组的最小值((n-k+1)个)形成的数组是否为一个排列
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair #define UM unordered_map typedef long long ll; const int mod=1e9+7; const int inf=0x3f3f3f3f; const ll INF=1e18; #define pi 3.1415926535898 #define DEC (pi/180) const int M=1e6+5; bool ans[M]; int a[M],cnt[M]; void py(){ puts("Yes"); } void pn(){ puts("No"); } int main(){ int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); for(int i=1;i<=n;i++) cnt[i]=0,ans[i]=false; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); cnt[a[i]]++; } int tot=1; for(int i=1;i<=n;tot++,i++){ if(!cnt[i]) break; } ans[1] = (tot==n+1 ? true : false); ans[n] = (cnt[1]>0 ? true : false); int l=1,r=n; for(int i=n;i>=1;i--){ int now=n-i+1; if(!cnt[now]) break; ans[i]=true; if(--cnt[now]==0&&(a[l]==now||a[r]==now)&&cnt[now+1]){ cnt[now]--; if(a[l]==now) l++; if(a[r]==now) r--; continue; } break; } for(int i=1;i<=n;i++)printf("%d",ans[i]); puts(""); } return 0; }
乘积的最短路,一般要转为对数log,变相地变成加的形式
关于auto :dfs函数和返回函数写法不一样:
/********dfs***********/ function<void(int)> dfs = [&](int u){ vis[u]=1; a.pb(u); for(auto v:g[u]){ if(!vis[v]) dfs(v); } }; /******不用调用自己的函数******/ auto Union = [&] (int x, int y) { x = find(x), y = find(y); if (x != y) { f[x] = y; return true; } return false; };
求b数组的每一项和a数组的n个数相加组成的n个数的gcd
考虑 gcd 的另一种计算方式,gcd(a1,a2,…,an)=gcd(a1,a2−a1,a3−a2,…,an−an−1),
那么就有 gcd(a1+x,a2+x,…,an+x)=gcd(a1+x,a2−a1,a3−a2,…,an−an−1),
预处理出 G=gcd(a2−a1,a3−a2,…,an−an−1),然后对于每组询问,输出 gcd(G,a1+bj) 即可。
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair #define UM unordered_map typedef long long ll; const int mod=1e9+7; const int inf=0x3f3f3f3f; const ll INF=1e18; #define pi 3.1415926535898 #define DEC (pi/180) const int M=3e5+5; ll a[M]; void pn(){ puts("NO"); } void py(){ puts("YES"); } int main(){ int n,m; cin>>n>>m; ll g=0,g2=0; for(int i=1;i<=n;i++){ cin>>a[i]; } sort(a+1,a+1+n); for(int i=1;i<=n;i++){ if(i>=2){ g2=__gcd(g2,a[i]-a[i-1]); } } for(int i=1;i<=m;i++){ ll x; cin>>x; cout<<__gcd(a[1]+x,g2)<<endl; } return 0; }
根据年月日判断星期
//基姆拉尔森计算公式根据日期判断星期几 void CalculateWeekDay(int y, int m,int d){ if(m==1||m==2) m+=12,y--; int iWeek = (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7; switch(iWeek){ case 0: printf("星期一\n"); break; case 1: printf("星期二\n"); break; case 2: printf("星期三\n"); break; case 3: printf("星期四\n"); break; case 4: printf("星期五\n"); break; case 5: printf("星期六\n"); break; case 6: printf("星期日\n"); break; } } int main() { CalculateWeekDay(2015,9,17); return 0; }
找ax+ay==aw+aq 范围n<=2e5. ai<=2e6(n*(n-1)/2种不同的sum 的可能 的 序列,而 组合最多时2*2e6,也就是n*(n-1)/2<=2*2e6,得到的n就很小了)
#include<bits/stdc++.h> using namespace std; const int M=998244353; const int N=5000005,E=524288; int n,a[N],i,j; struct str{ int x,y; }; vector<str> vis[N]; int main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif scanf("%d",&n); for(i=1;i<=n;++i) scanf("%d",&a[i]); for(i=1;i<=n;++i) for(j=1;j<=n-i;++j) { for(auto it:vis[a[j]+a[i+j]]) if(it.x!=j&&it.y!=i+j&&it.y!=j&&it.x!=i+j) { puts("YES"); printf("%d %d %d %d",it.x,it.y,j,i+j); return 0; } vis[a[j]+a[i+j]].push_back({j,i+j}); } puts("NO"); }
找字典序最小的子序列并且是一个排列
https://ac.nowcoder.com/acm/contest/12606/E
#include<bits/stdc++.h> using namespace std; const int M=2e5+5; int vis[M],a[M],las[M],ans[M]; int main(){ int n,k; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]),las[a[i]]=i; int tot=0; for(int i=1;i<=n;i++){ if(vis[a[i]])continue; while(tot>=1&&ans[tot]>=a[i]&&las[ans[tot]]>=i) vis[ans[tot--]]=0; vis[a[i]]=1; ans[++tot]=a[i]; } for(int i=1;i<=tot;i++) printf("%d ",ans[i]); return 0; }
小圈序列n和大圈序列m无限循环,求pos1(在n中)和pos2(在m中)的最小相遇位置(crt扩展中国剩余定理)crt数组
练习:给定n个数的序列(各不相同) 和m个数的序列(各不相同),俩个都是无限循环的序列,问前缀恰好有k个不相同的个数 的位置是哪一个位置(n,m<=5e5,k<=1e12)
https://codeforces.com/contest/1501/problem/D
#include <bits/stdc++.h> using namespace std; #define pb emplace_back #define MP make_pair #define pii pair<int,int> #define pll pair<ll,ll> #define lson rt<<1 #define rson rt<<1|1 typedef long long ll; typedef double db; const int INF = 0x3f3f3f3f; const db eps = 1e-6; const int MAXN = 5e5 + 7; ll n,m,k; int p1[MAXN<<1],p2[MAXN<<1];//2 * max(n,m) 一个序列里面的数都不同保证了每一个数位置的唯一性 //二分 + crt /************exCRT*************/ ll gcd(ll a,ll b) { return b == 0 ? a : gcd(b,a%b); } ll exgcd(ll a,ll b,ll &x,ll &y) { if(b == 0) { x = 1,y = 0; return a; } else { ll res = exgcd(b,a%b,x,y); ll t = x; x = y; y = t - a / b * y; return res; } } ll excrt(ll m1,ll m2,ll a1,ll a2) {//解决模数不互质的情况 ll x,y,c,g; c = a2 - a1; g = exgcd(m1,m2,x,y); x = x * c / g;//把方程右侧化为 y = m2 / g; x = (x % y + y) % y;//求最小正整数解 a1 = a1 + x * m1; m1 = m1 * m2 / g; return a1;//解x } /****************************/ ll crt[MAXN<<1],LCM; bool check(ll x) { ll sum = 0,ma = 2 * max(n,m); for(int i = 1;i <= ma;i ++) { if(!p1[i] || !p2[i]) continue; if(!crt[i] || x < crt[i]) continue;//别越界 //x通解 x = x0 + lcm(m1,m2); sum += (x - crt[i]) / LCM + 1;//看看后面还有几个通解 if(x - sum < k) return false; } return x - sum >= k;//总为x天,其中sum天相同,则x - sum天不同 } int main() { scanf("%lld%lld%lld",&n,&m,&k); for(int i = 1,x;i <= n;i ++) { scanf("%d",&x); p1[x] = i; } for(int i = 1,x;i <= m;i ++) { scanf("%d",&x); p2[x] = i; } ll ma = 2 * max(n,m),g = gcd(n,m); for(int i = 1;i <= ma;i ++) {//求解每一个值的最小出现的位置在哪 if(!p1[i] || !p2[i]) continue; if(abs(p1[i]-p2[i]) % g != 0) continue; crt[i] = excrt(n,m,p1[i],p2[i]);//存的是相等的值出现的位置 } LCM = n * m / g; ll l = 1,r = ma * k,ans;//ma * k就是相等比较多的极端情况 while(l <= r) { ll mid = (l + r) >> 1; if(check(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } printf("%lld\n",ans); return 0; }
从左上角到右下角有障碍(列数行数算组合数,障碍物容斥)
https://codeforces.com/problemset/problem/559/C
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair #define UM unordered_map #define pii pair<int,int> #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r #define lc root<<1 #define rc root<<1|1 typedef long long ll; const int mod=1e9+7; const int inf=0x3f3f3f3f; const ll INF=1e18; const int N=2002; const int M=2e5+5; #define pi 3.1415926535898 #define DEC (pi/180) struct node{ int x,y; }a[N]; ll fac[M],inv[M],f[M]; ll ksm(ll x,ll y){ ll t=1; while(y){ if(y&1) t=t*x%mod; y>>=1; x=x*x%mod; } return t; } void init(int n){ fac[0]=inv[0]=1; for(int i=1;i<=n;i++){ fac[i]=(fac[i-1]*i)%mod; inv[i]=ksm(fac[i],mod-2); } } ll C(int n,int m){ if(n<0||m<0) return 0; return fac[n]*inv[n-m]%mod*inv[m]%mod; } int main(){ int h,w,k; scanf("%d%d%d",&h,&w,&k); for(int i=0;i<k;i++) scanf("%d%d",&a[i].x,&a[i].y); init(h+w); a[k].x=h, a[k].y=w; sort(a,a+k+1,[&](node A,node B){ if(A.x==B.x) return A.y<B.y; return A.x<B.x; }); for(int i=0;i<=k;i++){ f[i]=C(a[i].x-1+a[i].y-1,a[i].x-1);///(C(n+m,n)) ///减去已经算过的 for(int j=0;j<i;j++){ int n=a[i].x-a[j].x; int m=a[i].y-a[j].y; if(n>=0&&m>=0) f[i]=(f[i]-f[j]*C(n+m,n)%mod+mod)%mod; } } printf("%lld\n",f[k]); return 0; }
在mian中写函数auto
auto matches = [&](int i, int j) { if (i == 0) { return false; } if (p[j - 1] == '.') { return true; } return s[i - 1] == p[j - 1]; };
马拉车
class Solution { public: int getLongestPalindrome(string A, int n) { // write code here string B = ""; if(n==0) B="^$"; else{ B = '^'; for(int i = 0; i < n; i++){ B += '#'; B += A[i]; } B += "#$"; } int len = B.size(); vector<int>P(len,0); int C = 0, R = 0; for(int i = 1; i < len-1; i++){ int posi = 2 * C - i; if(R>i){ P[i] = min(R - i,P[posi]); } else{ P[i] = 0; } while(B[i - 1 - P[i]] == B[i + 1 + P[i]]) P[i]++; if(i + P[i] > R){ R = i + P[i]; C = i; } } int maxlen = 0, nowid = 0; for(int i = 1; i < len - 1; i++){ if(P[i] > maxlen){ maxlen = P[i]; nowid=i; } } ///cout<<A.substr((nowid-maxlen)/2,maxlen)<<endl; return maxlen; } };
单调栈
///[L[i],i]位置上的值都大于a[i] ///[i,R[i]]位置上的值都大于a[i] for(int i=1;i<=n;i++) l[i]=r[i]=i; for(int i=1;i<=n;i++) { while(l[i]-1>=1&&h[i]<=h[l[i]-1]) l[i]=l[l[i]-1]; } for(int i=n;i>=1;i--) { while(r[i]+1<=n&&h[i]<=h[r[i]+1]) r[i]=r[r[i]+1]; }