B-捧杯
受力分析。。。貼這題主要是因爲看到了向量化簡有一個很簡潔的作法~
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int gcd(int a,int b)
{
if (a==0||b==0) {
return max(a+b,1);//cool~
}
while (b) {
int t=b;
b=a%b;
a=t;
}
return a;
}
void spfy(int &a,int &b)
{
int g=gcd(abs(a),abs(b));
a/=g;b/=g;
}
int main()
{
int T;
scanf("%d",&T);
while (T--) {
int x0,y0,n;
int ansx=0,ansy=0;
scanf("%d%d",&x0,&y0);
scanf("%d",&n);
for (int i=1;i<=n;i++) {
int x,y;
scanf("%d%d",&x,&y);
ansx+=x-x0;
ansy+=y-y0;
}
spfy(ansx,ansy);
printf("%d %d\n",ansx,ansy);
}
return 0;
}
C-汪老司機
交錯dp。。。
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=10010;
const ll INF=1LL<<60;
ll a[N],b[N];
ll f[N][20],g[N][20];
int main()
{
int T,n,k;
scanf("%d",&T);
while (T--) {
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++) {
scanf("%lld",&a[i]);
}
for (int i=1;i<=n;i++) {
scanf("%lld",&b[i]);
}
for (int i=1;i<=n;i++) {
f[i][0]=f[i-1][0]+a[i];
g[i][0]=g[i-1][0]+b[i];
}
for (int j=1;j<=k;j++) {
for (int i=1;i<=n;i++) {
f[i][j]=min(f[i-1][j]+a[i],g[i-1][j-1]+a[i]);
g[i][j]=min(g[i-1][j]+b[i],f[i-1][j-1]+b[i]);
}
}
printf("%lld\n",min(f[n][k],g[n][k]));
}
return 0;
}
D-蒟蒻的任務分配
這題是比賽的時候唯一沒什麼想法的。先貼一下通過某種py搞到的出題人的題解:
首先考慮到,沒有可容性的事件一定是不能同時進行的,也就是說,最短也要花費這些事件長度的總和,如果這些事件長度的總和是大於有可容性的事件的長度的總和,那麼最少耗費時間就是沒有可容性事件的長度總和
首先因爲最多同時開兩件事,那麼自然儘量把所有事分爲儘量相等的兩段,如果能夠安排出合理的方案,那麼該解一定是最優的。
接下來證明在這種條件下若分成儘量相等的兩段,總能夠安排出合理的序列使得任務能夠正常進行
假設分爲兩段第一段裏沒有可容性的事件總長爲x1,有可容性的事件的總長爲y1。第二段裏沒有可容性的事件總長爲x2,有可容性的事件的總長爲y2。那麼有x1+x2<=y1+y2不妨設x1+y1<=x2+y2那麼有如下安排方案先做第一段裏沒有可容性的事件,同時開始做第二段裏有可容性的事件如果y2 < x1,那麼根據x1+y1<=x2+y2,一定有x2>y1,那麼有x1+x2>y1+y2,與該情況相悖,所以y2>=x1。那麼在第一段沒有可容性的事件全部做完後,開始做第一段有可容性的事件然後在第二段有可容性的事件全部做完後,開始做第二段沒有可容性的事件隨後任務肯定能夠沒有衝突的順利進行,證畢。
接下來只需要把所有任務分爲時間儘量相等的兩半就可以了,這一部分可以揹包暴力跑01揹包時間複雜度是
O(t∗n2∗costi) 但是考慮到costi很小,可以記錄costi相等的事件的數量,然後做二進制優化優化後的時間複雜度爲O(t∗cost2∗nlogn) 本題放過了暴力01揹包的解法
不得不說這個想法很巧妙,反正我肯定是想不到的。
雖然出題人說01揹包能過但是我並沒有過。。。於是我還是寫了多重揹包。。。結果因爲沒清f[] WA了好幾次。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1005;
int cnt[20],f[N*10],s[2];
int main()
{
int T,n;
scanf("%d",&T);
while (T--) {
scanf("%d",&n);
s[0]=s[1]=0;
memset(f,0,sizeof(f));
memset(cnt,0,sizeof(cnt));
for (int i=1;i<=n;i++) {
int ci,fi;
scanf("%d%d",&ci,&fi);
s[fi]+=ci;
cnt[ci]++;
}
if (s[0]>s[1]) {
printf("%d\n",s[0]);
continue;
}
s[0]+=s[1];
int lim=s[0]/2;
for (int i=1;i<=10;i++) {
for (int k=1;k<=cnt[i];k<<=1) {
for (int j=lim;j>=k*i;j--) {
f[j]=max(f[j],f[j-k*i]+k*i);
}
cnt[i]-=k;
}
for (int j=lim;j>=cnt[i]*i;j--) {
f[j]=max(f[j],f[j-cnt[i]*i]+cnt[i]*i);
}
}
printf("%d\n",s[0]-f[lim]);
}
return 0;
}
還找到了一個理解起來難度可能小一點的方法:Problem D: 蒟蒻的任務分配 自行查閱
F-火柴棒
這題比賽的時候想的差不多了但是就是有一點沒想到。。。
首先總火柴數是偶數的話肯定都是1。
總火柴數是奇數的話:
- 如果其餘拼成奇數個1,把中間一個1變成7即可
- 如果其餘拼成偶數個1,把四個1和多餘的1根變爲三個7,放在首尾和中間;如果不到四個1,用兩個1和多餘的1根變爲一個5,可以發現這時總火柴數一定是5。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int w[10]={6,2,5,5,4,5,6,3,7,6};
char s[10010];
int main()
{
int T;
scanf("%d",&T);
while (T--) {
scanf("%s",s);
int l=strlen(s),sts=0;
for (int i=0;i<l;i++) {
sts+=w[s[i]-'0'];
}
// printf("%d\n",sts);
if (sts%2==0) {
int k=sts/2;
while (k--) {
putchar('1');
}
puts("");
continue;
}
int k=sts/2;
if (k&1) {
k/=2;
for (int i=1;i<=k;i++) {
putchar('1');
}
putchar('7');
for (int i=1;i<=k;i++) {
putchar('1');
}
puts("");
} else {
if (sts==5) {
puts("5");
continue;
}
k=k/2-1;
putchar('7');
for (int i=1;i<k;i++) {
putchar('1');
}
putchar('7');
for (int i=1;i<k;i++) {
putchar('1');
}
putchar('7');
puts("");
}
}
return 0;
}
G-PY
若有
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=100010;
long long a[N];
int main()
{
int T,n;
scanf("%d",&T);
while (T--) {
scanf("%d",&n);
for (int i=1;i<=n;i++) {
scanf("%lld",&a[i]);
}
ll ans=-1;
int pre=n;
for (int i=n-1;i>0;i--) {
ans=max(ans,a[i]+a[pre]+pre-i);
if (a[i]+i>a[pre]+pre) pre=i;
}
printf("%lld\n",ans);
}
return 0;
}
終於可以假裝自己AK了,over~
Coda
看到其他學校搞的比賽,不得不說比我們正式正規的多。。。
不過有底氣邀請全國的我們也不說了 =。= 話說那天給的網址是日本的服務器然後現在已經登不了了。。。FJNU 可以的,很66666