1001.我们的想法是,先构造n个要删掉的点,然后不断给图加边,使得每条边的其中一个点在n个点之中。
我们要使n个点之外的点尽量多,并且每次删掉的点在n个点之外。
贪心的决策是,每次操作,前n个点的度和令外的最大度的点度数相同。
然后删掉这个点之后,之后的操作,剩余的点也满足这个要求。所以度数最大的点必定与n个点有边。
于是可以这样构造,增加n批点(i = 1~n),每次增加n/i个点的,每个增加的点连出i条边到n个点。
这样,n个点每次增加的最大度数不超过1。但每次删点的时候(按n~1批的顺序),每删一批点,n个点度数都保证小于等于其余最大的度数。
#include<bits/stdc++.h> using namespace std; struct xxx { int x,y; xxx(int a,int b):x(a),y(b){}; }; vector<xxx> ans; int main() { ios::sync_with_stdio(0); int n = 20,cnt = n; for(int i = 1;i <= n;i++) { int now = 0,t = n/i; for(int j = 1;j <= t;j++) { cnt++; for(int k = 1;k <= i;k++) ans.push_back(xxx(++now,cnt)); } } cout << cnt << " " << ans.size() << endl; for(int i = 0;i < ans.size();i++) cout << ans[i].x << " " << ans[i].y << endl; cout << n << endl; for(int i = 1;i <= n;i++) cout << i << endl; return 0; }
1002.
1003.对原图和互补图bfs,找是否存在三元环,vector用short不会mle。
另外,根据Ramsey定理,n ≥ 6时,肯定存在三人互相认识或者三人互相不认识的情况。n < 6暴力判断即可。
#include<bits/stdc++.h> using namespace std; int n; bool a[3005][3005]; int main() { ios::sync_with_stdio(0); int T; scanf("%d",&T); while(T--) { memset(a,0,sizeof(a)); scanf("%d",&n); for(int i = 1;i < n;i++) { for(int j = i+1;j <= n;j++) scanf("%d",&a[i][j]); } if(n >= 6) { printf("Bad Team!\n"); continue; } else { int ok = 0; for(int i = 1;i <= n;i++) { for(int j = i+1;j <= n;j++) { for(int k = j+1;k <= n;k++) { if(a[i][j] == 1 && a[i][k] == 1 && a[j][k] == 1) ok = 1; if(a[i][j] == 0 && a[i][k] == 0 && a[j][k] == 0) ok = 1; } } } if(ok) printf("Bad Team!\n"); else printf("Great Team!\n"); } } return 0; }
1004.先把两个串reverse,然后跑kmp,统计每个数量的个数,注意最后一部分长度要加回来。
#include<bits/stdc++.h> #define MOD 1000000007 using namespace std; char s1[1000005],s2[1000005]; int cnt[1000005],ne[1000005]; void getnext1(char *s) { int i = 0,j = -1,len = strlen(s); ne[0] = -1; while(i < len) { if(j == -1 || s[i] == s[j]) ne[++i] = ++j; else j = ne[j]; } } void kmp(char *x,char *y) { getnext1(x); int i = 0,j = 0,leny = strlen(y),lenx = strlen(x); while(i < leny) { if(j == -1 || x[j] == y[i]) { i++,j++; if(j > 0) cnt[j]++; if(j == lenx) j = ne[j]; } else { j = ne[j]; if(j > 0) cnt[j]++; } } } int main() { ios::sync_with_stdio(0); int T; scanf("%d",&T); while(T--) { scanf("%s%s",s1,s2); int len1 = strlen(s1),len2 = strlen(s2); reverse(s1,s1+len1); reverse(s2,s2+len2); memset(cnt,0,sizeof(cnt)); kmp(s2,s1); long long ans = 0; for(int i = len2;i >= 1;i--) { ans = (ans+(long long)cnt[i]*i)%MOD; cnt[ne[i]] += cnt[i]; } printf("%lld\n",ans); } return 0; }
1005.n条边的最大面积计算分4种情况。二分答案,判断。
#include<bits/stdc++.h> using namespace std; int n; long long f(long long x) { long long t = x/4; if(x%4 == 0) return t*t*2; if(x%4 == 1) return t*t*2+(t+t-1)/2; if(x%4 == 2) return 2*t*(t+1); return 2*t*(t+1)+(t+t+1)/2; } int main() { ios::sync_with_stdio(0); int T; scanf("%d",&T); while(T--) { scanf("%d",&n); long long l = 4,r = 1e8; while(l < r) { long long mid = (l+r)/2; if(f(mid) >= n) r = mid; else l = mid+1; } printf("%lld\n",l); } return 0; }
1006.
1007.计算k进制1~n累计回文个数,在最高位之前的那些位没有限制,比较好算,最高位注意减一的情况。
#include<bits/stdc++.h> using namespace std; int l,r,x,y,a[105]; long long f(int n,int k) { int cnt = 0; long long x = n; while(x) { a[++cnt] = x%k; x /= k; } if(cnt == 0) return 0; long long ans = 0,now = 1; for(int i = 1;i < cnt;i += 2) { now *= k; ans += now-now/k; if(i+1 < cnt) ans += now-now/k; } long long t1 = 0; now = 1; for(int i = cnt;i > cnt/2;i--) { t1 = t1*k+a[i]; now *= k; } long long t2 = t1; int i = cnt%2?cnt/2+2:cnt/2+1; for(;i <= cnt;i++) t2 = t2*k+a[i]; if(t2 > n) ans += t1-now/k; else ans += t1-now/k+1; return ans; } int main() { ios::sync_with_stdio(0); int T; scanf("%d",&T); int z = 0; while(T--) { scanf("%d%d%d%d",&l,&r,&x,&y); long long ans = 0; for(int i = x;i <= y;i++) { ans += f(r,i)*(i-1)+r; ans -= f(l-1,i)*(i-1)+l-1; } printf("Case #%d: %lld\n",++z,ans); } return 0; }
CCPC 2017 网络赛
时间: 2024-10-05 19:25:32