1004
由于是相邻的数进行合并,很自然的想到了前缀和。这里dp[i]记录到i为止可以整除的整数。最初是超时了,后来剪了下枝就过了。
#include<bits/stdc++.h>
using namespace std;
int a[1000005];
int dp[1000005]={0};
int dis[10000005]={0};
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
int x,y;
memset(dp,0,sizeof(dp));
memset(dis,0,sizeof(dis));
cin>>x>>y;
for(int j=1;j<=x;j++){
scanf("%d",&a[j]);
if(a[j]%y!=0)
a[j]=a[j]%y;
else
a[j]=y;
dis[j]=dis[j-1]+a[j];
}
int maxx=0;
int p=0;
for(int j=1;j<=x;j++){
for(int m=p;m<j&&dis[j]-dis[m]>=y;m++){
int w=dis[j]-dis[m];
if(w%y==0){
dp[j]=max(dp[j],dp[m]+1);
}
}
dp[j]=max(dp[j],dp[j-1]);
if(dp[j]>maxx){
maxx=dp[j];
p=j;
}
}
printf("%d\n",dp[x]);
}
return 0;
}
1009
好吧,我是没懂为什么数组和堆会超时,而队列就过了。反正队友NB就对了。
#include<bits/stdc++.h>
using namespace std;
vector<int>que;
vector<int>kuo;
int main(){
int n;
string s;
cin>>n;
for(int i=1;i<=n;i++){
cin>>s;
que.clear();
kuo.clear();
int flag=0;
int l=0;
int r=0;
int h=s.length();
for(int j=0;j<h;j++){
if(s[j]=='('){
kuo.push_back(j);
}
else if(s[j]=='*'){
que.push_back(j);
}
else if(s[j]==')'){
if(l<kuo.size()){
kuo.erase(kuo.end()-1);
}
else if(r<que.size()){
int w=que[r];
s[w]='(';
r++;
}
else{
flag=1;
break;
}
}
}
for(int m=que.size()-1;m>=r&&!kuo.empty();m--){
int w=que[m];
int e=kuo.size() ;
int q=kuo[e-1];
if(q>w){
flag=1;
break;
}
else
s[w]=')';
kuo.erase(kuo.end()-1);
}
if(!kuo.empty())
flag=1;
if(flag==1)
cout<<"No solution!";
else{
for(int i=0;i<s.length();i++){
if(s[i]!='*')
cout<<s[i];
}
}
cout<<endl;
}
return 0;
}
1005
(没用组合数,之间是每次连一条边减去可能性)
刚开始的思路是减法,先算出总可能,之后每连一条边就减去失去的可能。当时不知道为什么一直没想出来可能性怎么减少。现在却有了思路。
用合并集的思路,把所有点看为一个独立的块。每当合并时,减少的情况只有合并的两个块与(把外面其他数看成一个整体)外面的块,各取一个数的情况。
证明一下:把要合并的块设为a,b;外面的整体看为c。
首先有一个块取两个的情况,a和b均不可能取2个(条件是两个数不能连通),c取两个与a和b中取一个的情况和a和b合并后取一个的情况是一样的。
一个块取三个的情况,只有c能取,又与a和b合并无关。
接下来各取一个有4种减小的情况:
1.a,b,c都取2。
2.a,b取2,c取1
3.a,c取2,b取1
4.b,c取2,a取1
之后是代码(需要快读和记忆化,不然会超时)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;
int fa[N],a[N],num1[N],num2[N];
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int main(){
int t;
t=read();
while(t--){
ll cnt1=0,cnt2=0,n;
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
if(a[i]==1)cnt1++,num1[i]=1,num2[i]=0;
else cnt2++,num1[i]=0,num2[i]=1;
fa[i]=i;
}
ll ans=(cnt2*(cnt2-1)*(cnt2-2)/6+cnt2*(cnt2-1)*cnt1/2);
printf("%lld\n",ans%mod);
for(int i=1;i<n;i++){
int u,v;
u=read(),v=read();
int x=find(u),y=find(v);
ans-=num2[x]*num2[y]*(cnt2-num2[x]-num2[y]);
ans-=num2[x]*num2[y]*(cnt1-num1[x]-num1[y]);
ans-=num1[x]*num2[y]*(cnt2-num2[x]-num2[y]);
ans-=num2[x]*num1[y]*(cnt2-num2[x]-num2[y]);
printf("%lld\n",ans%mod);
fa[y]=x;
num1[x]+=num1[y];
num2[x]+=num2[y];
}
}
}
1007
当时没时间,只粗略的看了,求的是去掉k条边后的最大最短路径问题。结果是k的值较小,只要暴力搜索就行,每次搜索时都去掉最短路径上的一条边。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=1e9+7;
int t,pre[10][55],vis[55],n,k;
ll a[55][55],dis[55];
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
ll ans;
ll spfa(int x){
for(int i=1;i<=n;i++)dis[i]=inf,pre[x][i]=-1,vis[i]=0;
dis[1]=0;
queue<int>q;
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=1;i<=n;i++){
if(u!=i&&dis[i]>dis[u]+a[u][i]){
pre[x][i]=u;
dis[i]=dis[u]+a[u][i];
if(vis[i]==0){
vis[i]=1;
q.push(i);
}
}
}
}
return dis[n];
}
void dfs(int x){
if(x==0){
ans=max(ans,spfa(x));
return;
}
spfa(x);
int v=n;
while(pre[x][v]!=-1){
int u=pre[x][v];
ll temp=a[u][v];
a[u][v]=a[v][u]=inf;
dfs(x-1);
a[u][v]=a[v][u]=temp;
v=u;
}
}
int main(){
t=read();
while(t--){
ans=0;
n=read(),k=read();
int len=n*(n-1)/2;
for(int i=1;i<=len;i++){
int u,v,w;
u=read(),v=read(),w=read();
a[u][v]=w,a[v][u]=w;
}
dfs(k);
printf("%lld\n",ans);
}
}