【CF】20十月CF刷題之旅
想了想感覺每次CF都發一篇文章挺浪費的,就把一個月的刷題都總結在這裡。想了想,就算不搞ACM,還是儘量把自己cf分保持在1900+能保持演算法狀態(也有可能是痴心妄想hhhh)
【CF】 Educational Codeforces Round 115 (Rated for Div. 2)
D
如果直接選就是C(n,3),然後考慮限制條件,可以發現不滿足的三元對為(Xa,Ya),(Xa,Yb),(Xb,Yb)然後我們發現三元組中中間那個特別,其餘的兩個都分別有一個變數與之相同。那麼最後找不滿足的三元對時,我們列舉中間那個,對於它為中間不滿足的就是(cntx[Xa]-1) * (cnty[Yb]-1),關於cnt預統計一下即可。
點選檢視程式碼
typedef long long ll; ll n; int cta[200005],ctb[200005]; int aa[200005],bb[200005]; ll ans; void sol() { scanf("%lld",&n); for(int i=1;i<=n;i++) ctb[i]=cta[i] = 0; for(int i=1;i<=n;i++) { int a,b; scanf("%d%d",&a,&b); aa[i] = a; bb[i] = b; cta[a]++; ctb[b]++; } ans = 1ll * n * (n-1) * (n-2)/6ll; for(int i=1;i<=n;i++) { ans -= 1ll*(cta[aa[i]]-1) * (ctb[bb[i]]-1); } printf("%lld\n",ans); } int main(){ int t; scanf("%d",&t); while(t--) { sol(); } }
E
設f[x][y][down/right]表示方案數,最後一個下來是往下轉下來還是往右轉下來的。有f[x][y][down]=f[x-1][y][right]+1 , f[x][y][right]=f[x][y-1][down]+1,那麼可以O(nm)計算出初始的總方案數(注意直接所有方案數加起來把單格子計算了兩次),之後每次修改,因為我們發現對於一個狀態轉移是唯一的,並且發現每次修改影響的格子並不多,那麼我們每次暴力更新一下DP,O(nq)就可以了。
點選檢視程式碼
typedef long long ll; const int maxn = 1005; int n,m,q; ll f[maxn][maxn][2]; //0 down 1 right 是如何到(x,y) bool blo[maxn][maxn]; ll ANS,freecnt; void dfs(int x,int y,int did) { if(blo[x][y]||x>n||y>m) return; ANS -= f[x][y][did]; if(did==1) { f[x][y][1] = f[x][y-1][0] + 1; dfs(x+1,y,0); } else { f[x][y][0] = f[x-1][y][1] + 1; dfs(x,y+1,1); } ANS += f[x][y][did]; } int main(){ scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { f[i][j][0] = f[i-1][j][1] + 1; f[i][j][1] = f[i][j-1][0] + 1; ANS += f[i][j][0] + f[i][j][1]; } } freecnt = 1ll*n*m; while (q--) { int x,y; scanf("%d%d",&x,&y); if(blo[x][y]){ blo[x][y] ^= 1; f[x][y][0] = f[x-1][y][1]+1; f[x][y][1] = f[x][y-1][0]+1; ANS+=f[x][y][0]+f[x][y][1]; dfs(x+1,y,0); dfs(x,y+1,1); freecnt++; } else { blo[x][y] ^= 1; ANS -= f[x][y][0] + f[x][y][1]; f[x][y][0] = f[x][y][1] = 0; dfs(x+1,y,0); dfs(x,y+1,1); freecnt--; } printf("%lld\n",ANS-freecnt); } return 0; }
Codeforces Round #745 (Div. 1)
A
突然發現出題者是我母校的學弟大佬,%%%
沒做出來,本題基本參考
仔細分析發現這好像就是求O(N^3)最大二維字首和?列舉上界,下界,然後列舉r,順便更新最優字首和,來避免O(n^4)列舉。。。還是太菜了。
點選檢視程式碼
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<set>
#include<map>
#include<cmath>
#include<random>
#include<ctime>
#include<complex>
#include<iomanip>
using namespace std;
const int maxn = 405;
int n,m;
char ss[maxn];
int a[maxn][maxn],sm[maxn][maxn];
int gsum(int xa,int ya,int xb,int yb) {
return sm[xb][yb] - sm[xa-1][yb] - sm[xb][ya-1] + sm[xa-1][ya-1];
}
int ANS;
int hanbao(int xa,int ya,int xb,int yb) {
return gsum(xa+1,ya,xb-1,yb) + (yb-ya+1)*2-gsum(xa,ya,xa,yb)-gsum(xb,ya,xb,yb);
}
int clac(int up,int dw,int i) {
return dw-up-1-gsum(up+1,i,dw-1,i);
}
void sol() {
scanf("%d%d",&n,&m);
ANS = n*m;
for(int i=1;i<=n;i++) {
scanf("%s",&ss[1]);
for(int j=1;j<=m;j++) {
a[i][j] = ss[j]-'0';
sm[i][j] = sm[i-1][j]+sm[i][j-1]-sm[i-1][j-1]+a[i][j];
}
}
for(int up=1;up<=n;up++) {
for(int dw=up+4;dw<=n;dw++) {
int maxpre = -n*m;
for(int i=4;i<=m;i++) {
maxpre = max(maxpre,hanbao(up,1,dw,i-3)-clac(up,dw,i-3));
ANS = min(ANS,hanbao(up,1,dw,i-1)+clac(up,dw,i)-maxpre);
}
}
}
printf("%d\n",ANS);
}
int main(){
int t;
scanf("%d",&t);
while(t--) sol();
return 0;
}
Codeforces Round #748 (Div. 3)
div3都打不明白,大概是真的廢了。
D2
做法有兩個。。一個是n^5(實際完全打不到),一個是2e6*n。
第一個做法就是設揹包s[i][k]表示從1到i,取了k個數,包含的所有公共gcd,(把它們全部放在set裡),然後每次擴充套件往後取就可以了。這樣我們就可以從s[x][n/2]中找到滿足的最大答案
第二個做法。。直接爆枚所有的mod,然後O(n)驗證。。。。(考場上真是傻子沒想到cxxx)。
法一
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<set>
#include<map>
#include<cmath>
#include<random>
#include<ctime>
#include<complex>
#include<iomanip>
using namespace std;
int gcd(int a,int b) {
return (!b)?a:gcd(b,a%b);
}
int n;
int a[45];
set<int>se[45][45];
void sol() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
se[0][0].insert(0);
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) se[i][j].clear();
}
for(int i=1;i<=n;i++) {
for(int j=0;j<=i-1;j++) {
for(int k=1;k<=i;k++) {
for(auto it:se[j][k-1]) {
int oo;
if(j==0) oo = 0;
else oo = gcd(a[i]-a[j],it);
if(!se[i][k].count(oo))
se[i][k].insert(oo);
}
}
}
}
int ANS = 1;
for(int i=n/2;i<=n;i++) {
if(!se[i][n/2].empty()) {
if(*se[i][n/2].begin()==0) {
puts("-1"); return;
}
ANS = max(ANS,*se[i][n/2].rbegin());
}
}
printf("%d\n",ANS);
}
int main() {
int t;
scanf("%d",&t);
while(t--) sol();
}
2
法二
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<set>
#include<map>
#include<cmath>
#include<random>
#include<ctime>
#include<complex>
#include<iomanip>
using namespace std;
const int MM = 2000005;
int n;
int a[45],b[45]; int cnt[MM];
void sol() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int mod = MM;mod>=1;mod--) {
int bst = 0;
for(int i=1;i<=n;i++) {
b[i] = a[i]%mod;
if(b[i]<0) b[i]+=mod;
cnt[b[i]]++;
bst = max(bst,cnt[b[i]]);
}
for(int i=1;i<=n;i++) cnt[b[i]]--;
if(bst>=n/2) {
if(mod==MM) puts("-1");
else printf("%d\n",mod);
return;
}
}
}
int main(){
int t;
scanf("%d",&t);
while (t--) {
sol();
}
return 0;
}