比賽網址
https://vjudge.net/contest/350953
首先:因爲突然去世,導致體驗極差,等活過來就可以看到提交結果了(這誰想得到呢,昨天還是活的)
A.1228
原題鏈接:
https://codeforces.com/problemset/problem/1228/A
題意:
給定一個區間),讓你取區間中任意一個數,要求的每一位數字都不相同,不存在這樣的數則輸出。
思路:
暴力判斷即可。
標程:
#include <bits/stdc++.h>
using namespace std;
int main() {
int l, r;
scanf("%d%d", &l, &r);
for (int i = l; i <= r; ++i) {
int book[15] = {0}, temp = i, flag = 0;
while (temp) {
book[temp % 10]++;
if (book[temp % 10] == 2) {
flag = 1;
break;
}
temp /= 10;
}
if (!flag)
return !printf("%d\n", i);
}
return !printf("-1\n");
}
B.1118
原題鏈接:
https://codeforces.com/contest/1118/problem/B
題意:
給個數,問依次刪去一個數後,剩下的數的奇數位置上的和和偶數位置上的和相等的有多少個。
思路:
是對於刪除第位數的話,第位之前的奇偶性是不變的,第位之後的奇偶性是和原來相反的,所以我們用前綴和,分別求出奇數位置上的前綴和和偶數位置上的前綴和,然後對於第位刪除掉了以後就是判斷一下前位的奇數前綴和加上後面偶數位的前綴和是否等於前位的偶數前綴和加上後面奇數位置的前綴和。
標程:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 10;
int a[N], odd[N], even[N];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
odd[1] = a[1];
even[1] = 0;
for (int i = 2; i <= n; i++) {
if (i & 1) {
odd[i] = a[i] + odd[i - 1];
even[i] = even[i - 1];
} else {
odd[i] = odd[i - 1];
even[i] = even[i - 1] + a[i];
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (odd[i - 1] + even[n] - even[i] == even[i - 1] + odd[n] - odd[i]) {
ans++;
}
}
printf("%d\n", ans);
return 0;
}
C.1559
原題鏈接:
http://acm.hdu.edu.cn/showproblem.php?pid=1559
題意:
給你一個的整數矩陣,在上面找一個的子矩陣,使子矩陣中所有元素的和最大。
思路;
預處理二維前綴和然後查詢就行了。
標程:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3 + 5;
const int inf = 0x3f3f3f3f;
ll a[N][N];
int main() {
int t, m, n, x, y;
ll ans;
scanf("%d", &t);
while (t--) {
ans = -inf;
scanf("%d%d%d%d", &n, &m, &x, &y);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%lld", &a[i][j]);
a[i][j] = a[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
}
}
//從i,j開始 到 i+x-1,j+y-1
for (int i = 1; i <= m - x + 1; i++) {
for (int j = 1; j <= n - y + 1; j++) {
ans = max(ans, a[i + x - 1][j + y - 1] - a[i + x - 1][j - 1] - a[i - 1][j + y - 1] + a[i - 1][j - 1]);
}
}
printf("%lld\n", ans);
}
return 0;
}
D.2456
原題鏈接:
http://poj.org/problem?id=2456
題意:
有個地方,有頭牛,一頭牛隻能分配一個地方,問如何分配使得所有牛之間的距離最小的那個值最大,是多少。
思路:
求最小值的最大值,先對隔間的位置進行排序,隔間之間的最小值最大爲最後那個隔間的位置減去第一個隔間的位置,這樣的話我們就可以二分了,判斷每倆頭牛之間最小相距距離時,能否裝下頭牛,如何判斷也是一個值得注意的地方,肯定要把第一個隔間的位置放一頭牛,貪心的思想,然後判斷下一個隔間的位置與上一個放牛的位置的距離是否大於等於,符合條件則放入,並把上一個放牛的位置改爲當前位置。
標程:
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N];
int n,m;
int judge(int x) {
int num=1;
int pos=a[1];
for(int i=2; i<=n; i++) {
if(a[i]-pos>=x) {
num++;
pos=a[i];
}
}
return num>=m;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
int l=0,r=1e9;
int ans;
while(l<=r) {
int mid=(l+r)/2;
if(judge(mid)) {
l=mid+1;
ans=mid;
} else {
r=mid-1;
}
}
printf("%d\n",ans);
return 0;
}
E.1988
原題鏈接:
http://poj.org/problem?id=1988
題意:
給定個方塊,排成一行,將它們編號到。再給出個操作:
① 表示將i所在的那一堆移到j所在那一堆的頂上。
② 表示一個詢問,詢問下面有多少個方塊。
思路:
帶權並查集,一堆中最頂上的方塊作爲父節點,用 統計X到父親節點的距離,表示這個集合的大小,兩者相減即爲答案。
標程:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int inf = 0x3f3f3f3f;
const int N = 300010;
const double pi = acos(-1.0);
int pre[N],num[N],dis[N];
int n;
void init() {
for(int i=0; i<n; i++) {
pre[i]=i;
num[i]=1;
dis[i]=0;
}
}
int Find(int x) {
if(x!=pre[x]) {
int t=pre[x];
pre[x]=Find(pre[x]);
dis[x]+=dis[t];
}
return pre[x];
}
int main() {
while(~scanf("%d",&n)) {
init();
char op;
while(n--) {
scanf(" %c",&op);
int x,y;
if(op=='M') {
scanf("%d %d",&x,&y);
int fx=Find(x);
int fy=Find(y);
if(fx!=fy) {
pre[fy]=fx;
dis[fy]=num[fx];
num[fx]+=num[fy];
}
} else {
scanf("%d",&x);
int fx=Find(x);
printf("%d\n",num[fx]-dis[x]-1);
}
}
}
return 0;
}
F.1421
原題鏈接:
http://acm.hdu.edu.cn/showproblem.php?pid=1421
題意:
從()個數中選出k對數(即個),使它們的差的平方和最小。
思路:
顯然,如果要讓疲勞度最低那麼一定要選擇重量相鄰的,所以要對所有的物品按照重量進行一次排序
用個物品,從中挑對物品的最小可能疲勞度,顯然這個狀態只能來自於和兩種,分別處理。
狀態轉移方程式爲:
,
標程:
#include<bits/stdc++.h>
using namespace std;
const int inf = 0xfffffff;
const int N = 2e3+10;
int a[N],dp[N][N];
int main() {
int n,k;
while(cin>>n>>k) {
for(int i=0; i<n; i++) {
cin >> a[i];
}
for(int i=0; i<=n; i++) {
for(int j=0; j<=k; j++) {
j == 0 ? dp[i][j] = 0 :dp[i][j] = inf;
}
}
sort(a,a+n);
for(int i=2; i<=n; i++) {
for(int j=1; j<=k&&j<=i; j++) {
dp[i][j] = min(dp[i-1][j], dp[i-2][j-1] + (a[i-1]-a[i-2])*(a[i-1]-a[i-2]));
}
cout << dp[n][k] << endl;
}
}
return 0;
}
G.1376
原題鏈接:
http://poj.org/problem?id=1376
題意:
給定地圖、起點、終點、初始方向,從起點開始每次操作能夠向當前方向前進1~3格或者旋轉90度改變方向,問最少需要幾次操作才能到達終點。
思路;
先轉換地圖,開一個數組,當遇到不能走的方格的時候即輸入值爲的時候,就把此時的 與看成點,,這樣標記完成以後,這個面就變成了一個個點,並且此時的機器人是有半徑的,所以在走的時候不可能走到邊界上,然後就行了。要注意一次能走格。
標程:
#include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
using namespace std;
struct note {
int x,y,id,s;
bool operator == (const note &a) const {
return a.y==y&&a.x==x;
}
} st,ed;
int vis[100][100][10];
int mp[100][100];
int n,m;
int dir[4][2]= {0,1,1,0,0,-1,-1,0};
int check(int x,int y,int id) {
if(x>0&&y>0&&x<n&&y<m&&vis[x][y][id]==0)
return 1;
return 0;
}
int bfs() {
queue<note>Q;
memset(vis,0,sizeof(vis));
st.s=0;
Q.push(st);
note now,temp;
while(!Q.empty()) {
now=Q.front();
Q.pop();
if(now==ed) {
printf("%d\n",now.s);
return 1;
}
temp=now;
temp.s++;
temp.id=(temp.id+1)%4;
if(vis[temp.x][temp.y][temp.id]==0) {
vis[temp.x][temp.y][temp.id]=1;
Q.push(temp);
}
temp=now;
temp.s++;
temp.id=(temp.id-1+4)%4;
if(vis[temp.x][temp.y][temp.id]==0) {
vis[temp.x][temp.y][temp.id]=1;
Q.push(temp);
}
for(int i=1; i<=3; i++) {
temp=now;
temp.x=now.x+dir[temp.id][0]*i;
temp.y=now.y+dir[temp.id][1]*i;
if(mp[temp.x][temp.y]==1)break;
if(check(temp.x,temp.y,temp.id)) {
temp.s++;
vis[temp.x][temp.y][temp.id]=1;
Q.push(temp);
}
}
}
return 0;
}
int main() {
while(~scanf("%d%d",&n,&m)&&(n+m)) {
int t;
memset(mp,0,sizeof(mp));
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
scanf("%d",&t);
if(t==1) {
mp[i][j]=mp[i+1][j]=mp[i][j+1]=1;
mp[i+1][j+1]=1;
}
}
}
scanf("%d%d%d%d",&st.x,&st.y,&ed.x,&ed.y);
char mp[20];
scanf("%s",mp);
if(mp[0]=='s')
st.id=1;
else if(mp[0]=='e')
st.id=0;
else if(mp[0]=='w')
st.id=2;
else
st.id=3;
if(bfs()==0)
printf("-1\n");
}
return 0;
}
H.6221
原題鏈接:
https://codeforces.com/problemset/problem/622/A
題意:
一個序列是這樣排的,求第個是什麼數字。
思路:
第個位置屬於到,求出,然後就是答案了。
方法1:可以枚舉爲,當大於等於時,就是了。
方法2:先讓,如果,那正確的應該。
標程:
- 方法
#include <cstdio>
typedef long long ll;
int main() {
ll n,k=1;
scanf("%lld",&n);
while(k) {
if(k*(k+1)/2>=n)break;
k++;
}
printf("%lld\n",n-k*(k-1)/2);
return 0;
}
- 方法
#include<cstdio>
#include<cmath>
typedef long long ll;
int main() {
ll n,k;
scanf("%lld",&n);
k=floor(sqrt(2*n));
if (k*(k+1)/2<n)k++;
printf("%lld",n-k*(k-1)/2);
return 0;
}
I.1263
原題鏈接:
https://codeforces.com/problemset/problem/1263/C
題意:
給一個讓你找向下取整可以得到的值。
思路:
有所以我們暴力枚舉肯定是不超時的,但是數組會存不下,這裏我們會發現一個規律就是枚舉到i是和的值一樣時,後面所有的都會存在。
標程:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e7;
int ans[N];
int main() {
int T;
scanf("%d",&T);
while(T--) {
ll n;
scanf("%lld",&n);
int cut=0;
for(int l=1,r; l<=n; l=r+1) {
r=n/(n/l);
ans[cut++]=n/l;
}
ans[cut++]=0;
printf("%d\n",cut);
sort(ans,ans+cut);
for(int i=0; i<cut; ++i) {
printf("%d ",ans[i]);
}
printf("\n");
}
return 0;
}
J.1278
原題鏈接:
https://codeforces.com/problemset/problem/1278/B
題意:
對於個測試點,給兩個數和,作如下操作:
第 步可以挑一個數字加 ,問你最少多少步能讓兩個數字相等。
思路;
假設操作了次。那麼我們要保證$\frac{ (x+1)*x}{2} \leq abs(a-b) $。
假設最後加到了另外 ==。
應該是一個偶數這時候應該加了=。
這時候只需要保證爲偶數就有解。因爲和有相同的奇偶性,所以只需要滿足$abs(a-b)\leq \frac{(x+1)*x}{2} \frac{(x+1)*x}{2} +a+b$爲偶數即可,所以只需要從開始遍歷,滿足條件即可輸出答案。
標程:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int T;
scanf("%d",&T);
while(T--) {
ll a,b;
scanf("%lld%lld",&a,&b);
for(ll i=0;; i++) {
ll temp=(i+1)*i/2;
if(temp>=abs(a-b)&&(a+b+temp)%2==0) {
printf("%lld\n",i);
break;
}
}
}
return 0;
}
再次聲明,此次比賽爲寒假歡樂賽,旨在提高大家刷題興趣和督促大家學習,並不影響大家的正常集訓學習。